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);
1691 if (Variable.HoistedVariant != null)
1694 expr_unwrap.Emit (ec);
1696 if (Variable?.HoistedVariant != null)
1701 // Only to make verifier happy
1702 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1703 ec.Emit (OpCodes.Box, expr.Type);
1705 ec.Emit (OpCodes.Isinst, probe_type_expr);
1708 if (Variable != null) {
1709 bool value_on_stack;
1710 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1711 ec.Emit (OpCodes.Dup);
1712 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1713 value_on_stack = true;
1715 value_on_stack = false;
1718 if (Variable.HoistedVariant != null) {
1719 Variable.HoistedVariant.EmitAssignFromStack (ec);
1721 if (expr_unwrap != null) {
1722 ec.MarkLabel (no_value_label);
1723 } else if (!value_on_stack) {
1724 Variable.HoistedVariant.Emit (ec);
1728 // It's ok to have variable builder created out of order. It simplifies emit
1729 // of statements like while (condition) { }
1731 if (!Variable.Created)
1732 Variable.CreateBuilder (ec);
1734 Variable.EmitAssign (ec);
1736 if (expr_unwrap != null) {
1737 ec.MarkLabel (no_value_label);
1738 } else if (!value_on_stack) {
1745 protected override Expression DoResolve (ResolveContext rc)
1747 if (ResolveCommon (rc) == null)
1750 type = rc.BuiltinTypes.Bool;
1751 eclass = ExprClass.Value;
1753 if (probe_type_expr == null)
1754 return ResolveMatchingExpression (rc);
1756 var res = ResolveResultExpression (rc);
1757 if (Variable != null) {
1758 if (res is Constant)
1759 throw new NotImplementedException ("constant in type pattern matching");
1761 Variable.Type = probe_type_expr;
1762 var bc = rc as BlockContext;
1764 Variable.PrepareAssignmentAnalysis (bc);
1770 public override void FlowAnalysis (FlowAnalysisContext fc)
1772 base.FlowAnalysis (fc);
1774 if (Variable != null)
1775 fc.SetVariableAssigned (Variable.VariableInfo, true);
1778 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
1780 if (Variable == null) {
1781 base.FlowAnalysisConditional (fc);
1785 expr.FlowAnalysis (fc);
1787 fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
1788 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1790 fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
1793 protected override void ResolveProbeType (ResolveContext rc)
1795 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1796 if (ProbeType is PatternExpression) {
1797 ProbeType.Resolve (rc);
1802 // Have to use session recording because we don't have reliable type probing
1803 // mechanism (similar issue as in attributes resolving)
1805 // TODO: This is still wrong because ResolveAsType can be destructive
1807 var type_printer = new SessionReportPrinter ();
1808 var prev_recorder = rc.Report.SetPrinter (type_printer);
1810 probe_type_expr = ProbeType.ResolveAsType (rc);
1811 type_printer.EndSession ();
1813 if (probe_type_expr != null) {
1814 type_printer.Merge (rc.Report.Printer);
1815 rc.Report.SetPrinter (prev_recorder);
1819 var vexpr = ProbeType as VarExpr;
1820 if (vexpr != null && vexpr.InferType (rc, expr)) {
1821 probe_type_expr = vexpr.Type;
1822 rc.Report.SetPrinter (prev_recorder);
1826 var expr_printer = new SessionReportPrinter ();
1827 rc.Report.SetPrinter (expr_printer);
1828 ProbeType = ProbeType.Resolve (rc);
1829 expr_printer.EndSession ();
1831 if (ProbeType != null) {
1832 expr_printer.Merge (rc.Report.Printer);
1834 type_printer.Merge (rc.Report.Printer);
1837 rc.Report.SetPrinter (prev_recorder);
1841 base.ResolveProbeType (rc);
1844 Expression ResolveMatchingExpression (ResolveContext rc)
1846 var mc = ProbeType as Constant;
1848 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1849 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1854 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1856 var c = Expr as Constant;
1858 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1863 if (Expr.Type.IsNullableType) {
1864 expr_unwrap = new Nullable.Unwrap (Expr);
1865 expr_unwrap.Resolve (rc);
1866 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1867 } else if (ProbeType.Type == Expr.Type) {
1868 // TODO: Better error handling
1869 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1870 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1871 var helper = rc.Module.CreatePatterMatchingHelper ();
1872 number_mg = helper.NumberMatcher.Spec;
1875 // There are actually 3 arguments but the first one is already on the stack
1877 number_args = new Arguments (3);
1878 if (!ProbeType.Type.IsEnum)
1879 number_args.Add (new Argument (Expr));
1881 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1882 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1888 if (ProbeType is PatternExpression) {
1889 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1890 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1896 // TODO: Better error message
1897 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1901 Expression ResolveResultExpression (ResolveContext ec)
1903 if (Variable != null) {
1904 if (expr is NullLiteral) {
1905 ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
1909 CheckExpressionVariable (ec);
1912 TypeSpec d = expr.Type;
1913 bool d_is_nullable = false;
1916 // If E is a method group or the null literal, or if the type of E is a reference
1917 // type or a nullable type and the value of E is null, the result is false
1920 return CreateConstantResult (ec, false);
1922 if (d.IsNullableType) {
1923 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1924 if (!ut.IsGenericParameter) {
1926 d_is_nullable = true;
1930 TypeSpec t = probe_type_expr;
1931 bool t_is_nullable = false;
1932 if (t.IsNullableType) {
1933 if (Variable != null) {
1934 ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
1935 t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
1938 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1939 if (!ut.IsGenericParameter) {
1941 t_is_nullable = true;
1948 // D and T are the same value types but D can be null
1950 if (d_is_nullable && !t_is_nullable) {
1951 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1956 // The result is true if D and T are the same value types
1958 return CreateConstantResult (ec, true);
1961 var tp = d as TypeParameterSpec;
1963 return ResolveGenericParameter (ec, t, tp);
1966 // An unboxing conversion exists
1968 if (Convert.ExplicitReferenceConversionExists (d, t))
1972 // open generic type
1974 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1977 var tps = t as TypeParameterSpec;
1979 return ResolveGenericParameter (ec, d, tps);
1981 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1982 if (Variable != null) {
1983 ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
1985 ec.Report.Warning (1981, 3, loc,
1986 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1987 OperatorName, t.GetSignatureForError ());
1991 if (TypeManager.IsGenericParameter (d))
1992 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1994 if (TypeSpec.IsValueType (d)) {
1995 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1996 if (d_is_nullable && !t_is_nullable) {
1997 expr_unwrap = Nullable.Unwrap.Create (expr, false);
2001 return CreateConstantResult (ec, true);
2004 if (Convert.ImplicitReferenceConversionExists (d, t)) {
2005 var c = expr as Constant;
2007 return CreateConstantResult (ec, !c.IsNull);
2010 // Do not optimize for imported type or dynamic type
2012 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
2013 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
2017 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
2021 // Turn is check into simple null check for implicitly convertible reference types
2023 return ReducedExpression.Create (
2024 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
2028 if (Convert.ExplicitReferenceConversionExists (d, t))
2032 // open generic type
2034 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
2039 return CreateConstantResult (ec, false);
2042 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
2044 if (t.IsReferenceType) {
2046 return CreateConstantResult (ec, false);
2049 if (expr.Type.IsGenericParameter) {
2050 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2051 return CreateConstantResult (ec, true);
2053 expr = new BoxedCast (expr, d);
2059 public override object Accept (StructuralVisitor visitor)
2061 return visitor.Visit (this);
2065 class WildcardPattern : PatternExpression
2067 public WildcardPattern (Location loc)
2072 protected override Expression DoResolve (ResolveContext rc)
2074 eclass = ExprClass.Value;
2075 type = rc.BuiltinTypes.Object;
2079 public override void Emit (EmitContext ec)
2085 class RecursivePattern : ComplexPatternExpression
2087 MethodGroupExpr operator_mg;
2088 Arguments operator_args;
2090 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2091 : base (typeExpresion, loc)
2093 Arguments = arguments;
2096 public Arguments Arguments { get; private set; }
2098 protected override Expression DoResolve (ResolveContext rc)
2100 type = TypeExpression.ResolveAsType (rc);
2104 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2105 if (operators == null) {
2106 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2110 var ops = FindMatchingOverloads (operators);
2112 // TODO: better error message
2113 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2118 Arguments.Resolve (rc, out dynamic_args);
2120 throw new NotImplementedException ("dynamic argument");
2122 var op = FindBestOverload (rc, ops);
2124 // TODO: better error message
2125 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2129 var op_types = op.Parameters.Types;
2130 operator_args = new Arguments (op_types.Length);
2131 operator_args.Add (new Argument (new EmptyExpression (type)));
2133 for (int i = 0; i < Arguments.Count; ++i) {
2134 // TODO: Needs releasing optimization
2135 var lt = new LocalTemporary (op_types [i + 1]);
2136 operator_args.Add (new Argument (lt, Argument.AType.Out));
2138 if (comparisons == null)
2139 comparisons = new Expression[Arguments.Count];
2144 var arg = Arguments [i];
2145 var named = arg as NamedArgument;
2146 if (named != null) {
2147 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2148 expr = Arguments [arg_comp_index].Expr;
2154 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2157 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2159 eclass = ExprClass.Value;
2163 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2165 int arg_count = Arguments.Count + 1;
2166 List<MethodSpec> best = null;
2167 foreach (MethodSpec method in members) {
2168 var pm = method.Parameters;
2169 if (pm.Count != arg_count)
2172 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2174 for (int ii = 1; ii < pm.Count; ++ii) {
2175 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2185 best = new List<MethodSpec> ();
2193 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2195 for (int ii = 0; ii < Arguments.Count; ++ii) {
2196 var arg = Arguments [ii];
2197 var expr = arg.Expr;
2198 if (expr is WildcardPattern)
2201 var na = arg as NamedArgument;
2202 for (int i = 0; i < methods.Count; ++i) {
2203 var pd = methods [i].Parameters;
2207 index = pd.GetParameterIndexByName (na.Name);
2209 methods.RemoveAt (i--);
2216 var m = pd.Types [index];
2217 if (!Convert.ImplicitConversionExists (rc, expr, m))
2218 methods.RemoveAt (i--);
2222 if (methods.Count != 1)
2228 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2230 operator_mg.EmitCall (ec, operator_args, false);
2231 ec.Emit (OpCodes.Brfalse, target);
2233 base.EmitBranchable (ec, target, on_true);
2236 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2238 if (expr is WildcardPattern)
2239 return new EmptyExpression (expr.Type);
2241 var recursive = expr as RecursivePattern;
2242 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2246 if (recursive != null) {
2247 recursive.SetParentInstance (lt);
2251 // TODO: Better error handling
2252 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2255 public void SetParentInstance (Expression instance)
2257 operator_args [0] = new Argument (instance);
2261 class PropertyPattern : ComplexPatternExpression
2263 LocalTemporary instance;
2265 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2266 : base (typeExpresion, loc)
2271 public List<PropertyPatternMember> Members { get; private set; }
2273 protected override Expression DoResolve (ResolveContext rc)
2275 type = TypeExpression.ResolveAsType (rc);
2279 comparisons = new Expression[Members.Count];
2281 // TODO: optimize when source is VariableReference, it'd save dup+pop
2282 instance = new LocalTemporary (type);
2284 for (int i = 0; i < Members.Count; i++) {
2285 var lookup = Members [i];
2287 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2288 if (member == null) {
2289 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2290 if (member != null) {
2291 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2296 if (member == null) {
2297 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2301 var pe = member as PropertyExpr;
2302 if (pe == null || member is FieldExpr) {
2303 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2307 // TODO: Obsolete checks
2308 // TODO: check accessibility
2309 if (pe != null && !pe.PropertyInfo.HasGet) {
2310 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2314 var expr = lookup.Expr.Resolve (rc);
2318 var me = (MemberExpr)member;
2319 me.InstanceExpression = instance;
2321 comparisons [i] = ResolveComparison (rc, expr, me);
2324 eclass = ExprClass.Value;
2328 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2330 if (expr is WildcardPattern)
2331 return new EmptyExpression (expr.Type);
2333 return new Is (instance, expr, expr.Location).Resolve (rc);
2336 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2338 instance.Store (ec);
2340 base.EmitBranchable (ec, target, on_true);
2344 class PropertyPatternMember
2346 public PropertyPatternMember (string name, Expression expr, Location loc)
2353 public string Name { get; private set; }
2354 public Expression Expr { get; private set; }
2355 public Location Location { get; private set; }
2358 abstract class PatternExpression : Expression
2360 protected PatternExpression (Location loc)
2365 public override Expression CreateExpressionTree (ResolveContext ec)
2367 throw new NotImplementedException ();
2371 abstract class ComplexPatternExpression : PatternExpression
2373 protected Expression[] comparisons;
2375 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2378 TypeExpression = typeExpresion;
2381 public ATypeNameExpression TypeExpression { get; private set; }
2383 public override void Emit (EmitContext ec)
2385 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2388 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2390 if (comparisons != null) {
2391 foreach (var comp in comparisons) {
2392 comp.EmitBranchable (ec, target, false);
2399 /// Implementation of the `as' operator.
2401 public class As : Probe {
2403 public As (Expression expr, Expression probe_type, Location l)
2404 : base (expr, probe_type, l)
2408 protected override string OperatorName {
2409 get { return "as"; }
2412 public override Expression CreateExpressionTree (ResolveContext ec)
2414 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2415 expr.CreateExpressionTree (ec),
2416 new TypeOf (probe_type_expr, loc));
2418 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2421 public override void Emit (EmitContext ec)
2425 ec.Emit (OpCodes.Isinst, type);
2427 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2428 ec.Emit (OpCodes.Unbox_Any, type);
2431 protected override Expression DoResolve (ResolveContext ec)
2433 if (ResolveCommon (ec) == null)
2436 type = probe_type_expr;
2437 eclass = ExprClass.Value;
2438 TypeSpec etype = expr.Type;
2440 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) {
2441 ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type");
2442 type = InternalType.ErrorType;
2447 type = InternalType.ErrorType;
2451 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2452 if (TypeManager.IsGenericParameter (type)) {
2453 ec.Report.Error (413, loc,
2454 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2455 probe_type_expr.GetSignatureForError ());
2457 ec.Report.Error (77, loc,
2458 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2459 type.GetSignatureForError ());
2464 if (expr.IsNull && type.IsNullableType) {
2465 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2468 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2469 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2473 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2475 e = EmptyCast.Create (e, type);
2476 return ReducedExpression.Create (e, this).Resolve (ec);
2479 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2480 if (TypeManager.IsGenericParameter (etype))
2481 expr = new BoxedCast (expr, etype);
2486 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2487 expr = new BoxedCast (expr, etype);
2491 if (etype != InternalType.ErrorType) {
2492 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2493 etype.GetSignatureForError (), type.GetSignatureForError ());
2499 public override object Accept (StructuralVisitor visitor)
2501 return visitor.Visit (this);
2506 // This represents a typecast in the source language.
2508 public class Cast : ShimExpression {
2509 Expression target_type;
2511 public Cast (Expression cast_type, Expression expr, Location loc)
2514 this.target_type = cast_type;
2518 public Expression TargetType {
2519 get { return target_type; }
2522 protected override Expression DoResolve (ResolveContext ec)
2524 expr = expr.Resolve (ec);
2528 type = target_type.ResolveAsType (ec);
2532 if (type.IsStatic) {
2533 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2537 if (type.IsPointer) {
2538 if (ec.CurrentIterator != null) {
2539 UnsafeInsideIteratorError (ec, loc);
2540 } else if (!ec.IsUnsafe) {
2541 UnsafeError (ec, loc);
2545 eclass = ExprClass.Value;
2547 Constant c = expr as Constant;
2549 c = c.Reduce (ec, type);
2554 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2556 return EmptyCast.Create (res, type);
2561 protected override void CloneTo (CloneContext clonectx, Expression t)
2563 Cast target = (Cast) t;
2565 target.target_type = target_type.Clone (clonectx);
2566 target.expr = expr.Clone (clonectx);
2569 public override object Accept (StructuralVisitor visitor)
2571 return visitor.Visit (this);
2575 public class ImplicitCast : ShimExpression
2579 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2582 this.loc = expr.Location;
2584 this.arrayAccess = arrayAccess;
2587 protected override Expression DoResolve (ResolveContext ec)
2589 expr = expr.Resolve (ec);
2594 expr = ConvertExpressionToArrayIndex (ec, expr);
2596 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2602 public class DeclarationExpression : Expression, IMemoryLocation
2604 LocalVariableReference lvr;
2606 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2608 VariableType = variableType;
2609 Variable = variable;
2610 this.loc = variable.Location;
2613 public LocalVariable Variable { get; set; }
2614 public Expression Initializer { get; set; }
2615 public FullNamedExpression VariableType { get; set; }
2617 public void AddressOf (EmitContext ec, AddressOp mode)
2619 if (!Variable.Created)
2620 Variable.CreateBuilder (ec);
2622 if (Initializer != null) {
2623 lvr.EmitAssign (ec, Initializer, false, false);
2626 lvr.AddressOf (ec, mode);
2629 protected override void CloneTo (CloneContext clonectx, Expression t)
2631 var target = (DeclarationExpression) t;
2633 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2635 if (Initializer != null)
2636 target.Initializer = Initializer.Clone (clonectx);
2639 public override Expression CreateExpressionTree (ResolveContext rc)
2641 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2645 bool DoResolveCommon (ResolveContext rc)
2647 CheckExpressionVariable (rc);
2649 var var_expr = VariableType as VarExpr;
2650 if (var_expr != null) {
2651 type = InternalType.VarOutType;
2653 type = VariableType.ResolveAsType (rc);
2658 if (Initializer != null) {
2659 Initializer = Initializer.Resolve (rc);
2661 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2662 type = var_expr.Type;
2666 Variable.Type = type;
2667 lvr = new LocalVariableReference (Variable, loc);
2669 eclass = ExprClass.Variable;
2673 protected override Expression DoResolve (ResolveContext rc)
2675 if (DoResolveCommon (rc))
2681 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2683 if (lvr == null && DoResolveCommon (rc))
2684 lvr.ResolveLValue (rc, right_side);
2689 public override void Emit (EmitContext ec)
2691 throw new NotImplementedException ();
2694 public override void EmitPrepare (EmitContext ec)
2696 Variable.CreateBuilder (ec);
2701 // C# 2.0 Default value expression
2703 public class DefaultValueExpression : Expression
2707 public DefaultValueExpression (Expression expr, Location loc)
2713 public Expression Expr {
2719 public override bool IsSideEffectFree {
2725 public override bool ContainsEmitWithAwait ()
2730 public override Expression CreateExpressionTree (ResolveContext ec)
2732 Arguments args = new Arguments (2);
2733 args.Add (new Argument (this));
2734 args.Add (new Argument (new TypeOf (type, loc)));
2735 return CreateExpressionFactoryCall (ec, "Constant", args);
2738 protected override Expression DoResolve (ResolveContext ec)
2740 type = expr.ResolveAsType (ec);
2744 if (type.IsStatic) {
2745 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2749 return new NullLiteral (Location).ConvertImplicitly (type);
2751 if (TypeSpec.IsReferenceType (type))
2752 return new NullConstant (type, loc);
2754 Constant c = New.Constantify (type, expr.Location);
2758 eclass = ExprClass.Variable;
2762 public override void Emit (EmitContext ec)
2764 LocalTemporary temp_storage = new LocalTemporary(type);
2766 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2767 ec.Emit(OpCodes.Initobj, type);
2768 temp_storage.Emit(ec);
2769 temp_storage.Release (ec);
2773 public override SLE.Expression MakeExpression (BuilderContext ctx)
2775 return SLE.Expression.Default (type.GetMetaInfo ());
2779 protected override void CloneTo (CloneContext clonectx, Expression t)
2781 DefaultValueExpression target = (DefaultValueExpression) t;
2783 target.expr = expr.Clone (clonectx);
2786 public override object Accept (StructuralVisitor visitor)
2788 return visitor.Visit (this);
2793 /// Binary operators
2795 public class Binary : Expression, IDynamicBinder
2797 public class PredefinedOperator
2799 protected readonly TypeSpec left;
2800 protected readonly TypeSpec right;
2801 protected readonly TypeSpec left_unwrap;
2802 protected readonly TypeSpec right_unwrap;
2803 public readonly Operator OperatorsMask;
2804 public TypeSpec ReturnType;
2806 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2807 : this (ltype, rtype, op_mask, ltype)
2811 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2812 : this (type, type, op_mask, return_type)
2816 public PredefinedOperator (TypeSpec type, Operator op_mask)
2817 : this (type, type, op_mask, type)
2821 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2823 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2824 throw new InternalErrorException ("Only masked values can be used");
2826 if ((op_mask & Operator.NullableMask) != 0) {
2827 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2828 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2830 left_unwrap = ltype;
2831 right_unwrap = rtype;
2836 this.OperatorsMask = op_mask;
2837 this.ReturnType = return_type;
2840 public bool IsLifted {
2842 return (OperatorsMask & Operator.NullableMask) != 0;
2846 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2850 var left_expr = b.left;
2851 var right_expr = b.right;
2853 b.type = ReturnType;
2856 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2857 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2858 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2861 if (right_expr.IsNull) {
2862 if ((b.oper & Operator.EqualityMask) != 0) {
2863 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2864 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2865 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2866 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2867 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2869 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2870 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2872 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2873 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2875 return b.CreateLiftedValueTypeResult (rc, left);
2877 } else if (left_expr.IsNull) {
2878 if ((b.oper & Operator.EqualityMask) != 0) {
2879 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2880 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2881 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2882 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2883 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2885 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2886 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2888 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2889 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2891 return b.CreateLiftedValueTypeResult (rc, right);
2897 // A user operators does not support multiple user conversions, but decimal type
2898 // is considered to be predefined type therefore we apply predefined operators rules
2899 // and then look for decimal user-operator implementation
2901 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2902 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2903 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2905 return b.ResolveUserOperator (rc, b.left, b.right);
2908 c = right_expr as Constant;
2910 if (c.IsDefaultValue) {
2914 // (expr + 0) to expr
2915 // (expr - 0) to expr
2916 // (bool? | false) to bool?
2918 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2919 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2920 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2921 return ReducedExpression.Create (b.left, b).Resolve (rc);
2925 // Optimizes (value &/&& 0) to 0
2927 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2928 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2929 return ReducedExpression.Create (side_effect, b);
2933 // Optimizes (bool? & true) to bool?
2935 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2936 return ReducedExpression.Create (b.left, b).Resolve (rc);
2940 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2941 return ReducedExpression.Create (b.left, b).Resolve (rc);
2943 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2944 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2948 c = b.left as Constant;
2950 if (c.IsDefaultValue) {
2954 // (0 + expr) to expr
2955 // (false | bool?) to bool?
2957 if (b.oper == Operator.Addition ||
2958 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2959 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2960 return ReducedExpression.Create (b.right, b).Resolve (rc);
2964 // Optimizes (false && expr) to false
2966 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2967 // No rhs side-effects
2968 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2969 return ReducedExpression.Create (c, b);
2973 // Optimizes (0 & value) to 0
2975 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2976 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2977 return ReducedExpression.Create (side_effect, b);
2981 // Optimizes (true & bool?) to bool?
2983 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2984 return ReducedExpression.Create (b.right, b).Resolve (rc);
2988 // Optimizes (true || expr) to true
2990 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2991 // No rhs side-effects
2992 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2993 return ReducedExpression.Create (c, b);
2997 if (b.oper == Operator.Multiply && c.IsOneInteger)
2998 return ReducedExpression.Create (b.right, b).Resolve (rc);
3002 var lifted = new Nullable.LiftedBinaryOperator (b);
3004 TypeSpec ltype, rtype;
3005 if (b.left.Type.IsNullableType) {
3006 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
3007 ltype = left_unwrap;
3012 if (b.right.Type.IsNullableType) {
3013 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
3014 rtype = right_unwrap;
3019 lifted.Left = b.left.IsNull ?
3020 Nullable.LiftedNull.Create (ltype, b.left.Location) :
3021 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
3023 lifted.Right = b.right.IsNull ?
3024 Nullable.LiftedNull.Create (rtype, b.right.Location) :
3025 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
3027 return lifted.Resolve (rc);
3030 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3031 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3036 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3039 // We are dealing with primitive types only
3041 return left == ltype && ltype == rtype;
3044 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3047 if (left == lexpr.Type && right == rexpr.Type)
3050 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3051 Convert.ImplicitConversionExists (ec, rexpr, right);
3054 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3056 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3057 return best_operator;
3059 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3063 if (left != null && best_operator.left != null) {
3064 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3068 // When second argument is same as the first one, the result is same
3070 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3071 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3074 if (result == 0 || result > 2)
3077 return result == 1 ? best_operator : this;
3081 sealed class PredefinedStringOperator : PredefinedOperator
3083 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3084 : base (type, type, op_mask, retType)
3088 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3089 : base (ltype, rtype, op_mask, retType)
3093 public override Expression ConvertResult (ResolveContext ec, Binary b)
3096 // Use original expression for nullable arguments
3098 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3100 b.left = unwrap.Original;
3102 unwrap = b.right as Nullable.Unwrap;
3104 b.right = unwrap.Original;
3106 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3107 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3110 // Start a new concat expression using converted expression
3112 return StringConcat.Create (ec, b.left, b.right, b.loc);
3116 sealed class PredefinedEqualityOperator : PredefinedOperator
3118 MethodSpec equal_method, inequal_method;
3120 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3121 : base (arg, arg, Operator.EqualityMask, retType)
3125 public override Expression ConvertResult (ResolveContext ec, Binary b)
3127 b.type = ReturnType;
3129 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3130 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3132 Arguments args = new Arguments (2);
3133 args.Add (new Argument (b.left));
3134 args.Add (new Argument (b.right));
3137 if (b.oper == Operator.Equality) {
3138 if (equal_method == null) {
3139 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3140 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3141 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3142 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3144 throw new NotImplementedException (left.GetSignatureForError ());
3147 method = equal_method;
3149 if (inequal_method == null) {
3150 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3151 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3152 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3153 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3155 throw new NotImplementedException (left.GetSignatureForError ());
3158 method = inequal_method;
3161 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3165 class PredefinedPointerOperator : PredefinedOperator
3167 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3168 : base (ltype, rtype, op_mask)
3172 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3173 : base (ltype, rtype, op_mask, retType)
3177 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3178 : base (type, op_mask, return_type)
3182 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3185 if (!lexpr.Type.IsPointer)
3188 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3192 if (right == null) {
3193 if (!rexpr.Type.IsPointer)
3196 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3203 public override Expression ConvertResult (ResolveContext ec, Binary b)
3206 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3207 } else if (right != null) {
3208 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3211 TypeSpec r_type = ReturnType;
3212 Expression left_arg, right_arg;
3213 if (r_type == null) {
3216 right_arg = b.right;
3217 r_type = b.left.Type;
3221 r_type = b.right.Type;
3225 right_arg = b.right;
3228 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3233 public enum Operator {
3234 Multiply = 0 | ArithmeticMask,
3235 Division = 1 | ArithmeticMask,
3236 Modulus = 2 | ArithmeticMask,
3237 Addition = 3 | ArithmeticMask | AdditionMask,
3238 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3240 LeftShift = 5 | ShiftMask,
3241 RightShift = 6 | ShiftMask,
3243 LessThan = 7 | ComparisonMask | RelationalMask,
3244 GreaterThan = 8 | ComparisonMask | RelationalMask,
3245 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3246 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3247 Equality = 11 | ComparisonMask | EqualityMask,
3248 Inequality = 12 | ComparisonMask | EqualityMask,
3250 BitwiseAnd = 13 | BitwiseMask,
3251 ExclusiveOr = 14 | BitwiseMask,
3252 BitwiseOr = 15 | BitwiseMask,
3254 LogicalAnd = 16 | LogicalMask,
3255 LogicalOr = 17 | LogicalMask,
3260 ValuesOnlyMask = ArithmeticMask - 1,
3261 ArithmeticMask = 1 << 5,
3263 ComparisonMask = 1 << 7,
3264 EqualityMask = 1 << 8,
3265 BitwiseMask = 1 << 9,
3266 LogicalMask = 1 << 10,
3267 AdditionMask = 1 << 11,
3268 SubtractionMask = 1 << 12,
3269 RelationalMask = 1 << 13,
3271 DecomposedMask = 1 << 19,
3272 NullableMask = 1 << 20
3276 public enum State : byte
3280 UserOperatorsExcluded = 1 << 2
3283 readonly Operator oper;
3284 Expression left, right;
3286 ConvCast.Mode enum_conversion;
3288 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3289 : this (oper, left, right, State.Compound)
3293 public Binary (Operator oper, Expression left, Expression right, State state)
3294 : this (oper, left, right)
3299 public Binary (Operator oper, Expression left, Expression right)
3300 : this (oper, left, right, left.Location)
3304 public Binary (Operator oper, Expression left, Expression right, Location loc)
3314 public bool IsCompound {
3316 return (state & State.Compound) != 0;
3320 public Operator Oper {
3326 public Expression Left {
3332 public Expression Right {
3338 public override Location StartLocation {
3340 return left.StartLocation;
3347 /// Returns a stringified representation of the Operator
3349 string OperName (Operator oper)
3353 case Operator.Multiply:
3356 case Operator.Division:
3359 case Operator.Modulus:
3362 case Operator.Addition:
3365 case Operator.Subtraction:
3368 case Operator.LeftShift:
3371 case Operator.RightShift:
3374 case Operator.LessThan:
3377 case Operator.GreaterThan:
3380 case Operator.LessThanOrEqual:
3383 case Operator.GreaterThanOrEqual:
3386 case Operator.Equality:
3389 case Operator.Inequality:
3392 case Operator.BitwiseAnd:
3395 case Operator.BitwiseOr:
3398 case Operator.ExclusiveOr:
3401 case Operator.LogicalOr:
3404 case Operator.LogicalAnd:
3408 s = oper.ToString ();
3418 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3420 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3423 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3425 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3429 l = left.Type.GetSignatureForError ();
3430 r = right.Type.GetSignatureForError ();
3432 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3436 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3438 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3441 public override void FlowAnalysis (FlowAnalysisContext fc)
3444 // Optimized version when on-true/on-false data are not needed
3446 if ((oper & Operator.LogicalMask) == 0) {
3447 left.FlowAnalysis (fc);
3448 right.FlowAnalysis (fc);
3452 left.FlowAnalysisConditional (fc);
3453 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3454 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3456 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3457 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3458 right.FlowAnalysisConditional (fc);
3460 if (oper == Operator.LogicalOr)
3461 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3463 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3466 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3468 if ((oper & Operator.LogicalMask) == 0) {
3469 base.FlowAnalysisConditional (fc);
3473 left.FlowAnalysisConditional (fc);
3474 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3475 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3477 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3478 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3479 right.FlowAnalysisConditional (fc);
3481 var lc = left as Constant;
3482 if (oper == Operator.LogicalOr) {
3483 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3484 if (lc != null && lc.IsDefaultValue)
3485 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3487 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3489 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3490 if (lc != null && !lc.IsDefaultValue)
3491 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3493 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3498 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3500 string GetOperatorExpressionTypeName ()
3503 case Operator.Addition:
3504 return IsCompound ? "AddAssign" : "Add";
3505 case Operator.BitwiseAnd:
3506 return IsCompound ? "AndAssign" : "And";
3507 case Operator.BitwiseOr:
3508 return IsCompound ? "OrAssign" : "Or";
3509 case Operator.Division:
3510 return IsCompound ? "DivideAssign" : "Divide";
3511 case Operator.ExclusiveOr:
3512 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3513 case Operator.Equality:
3515 case Operator.GreaterThan:
3516 return "GreaterThan";
3517 case Operator.GreaterThanOrEqual:
3518 return "GreaterThanOrEqual";
3519 case Operator.Inequality:
3521 case Operator.LeftShift:
3522 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3523 case Operator.LessThan:
3525 case Operator.LessThanOrEqual:
3526 return "LessThanOrEqual";
3527 case Operator.LogicalAnd:
3529 case Operator.LogicalOr:
3531 case Operator.Modulus:
3532 return IsCompound ? "ModuloAssign" : "Modulo";
3533 case Operator.Multiply:
3534 return IsCompound ? "MultiplyAssign" : "Multiply";
3535 case Operator.RightShift:
3536 return IsCompound ? "RightShiftAssign" : "RightShift";
3537 case Operator.Subtraction:
3538 return IsCompound ? "SubtractAssign" : "Subtract";
3540 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3544 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3547 case Operator.Addition:
3548 return CSharp.Operator.OpType.Addition;
3549 case Operator.BitwiseAnd:
3550 case Operator.LogicalAnd:
3551 return CSharp.Operator.OpType.BitwiseAnd;
3552 case Operator.BitwiseOr:
3553 case Operator.LogicalOr:
3554 return CSharp.Operator.OpType.BitwiseOr;
3555 case Operator.Division:
3556 return CSharp.Operator.OpType.Division;
3557 case Operator.Equality:
3558 return CSharp.Operator.OpType.Equality;
3559 case Operator.ExclusiveOr:
3560 return CSharp.Operator.OpType.ExclusiveOr;
3561 case Operator.GreaterThan:
3562 return CSharp.Operator.OpType.GreaterThan;
3563 case Operator.GreaterThanOrEqual:
3564 return CSharp.Operator.OpType.GreaterThanOrEqual;
3565 case Operator.Inequality:
3566 return CSharp.Operator.OpType.Inequality;
3567 case Operator.LeftShift:
3568 return CSharp.Operator.OpType.LeftShift;
3569 case Operator.LessThan:
3570 return CSharp.Operator.OpType.LessThan;
3571 case Operator.LessThanOrEqual:
3572 return CSharp.Operator.OpType.LessThanOrEqual;
3573 case Operator.Modulus:
3574 return CSharp.Operator.OpType.Modulus;
3575 case Operator.Multiply:
3576 return CSharp.Operator.OpType.Multiply;
3577 case Operator.RightShift:
3578 return CSharp.Operator.OpType.RightShift;
3579 case Operator.Subtraction:
3580 return CSharp.Operator.OpType.Subtraction;
3582 throw new InternalErrorException (op.ToString ());
3586 public override bool ContainsEmitWithAwait ()
3588 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3591 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3596 case Operator.Multiply:
3597 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3598 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3599 opcode = OpCodes.Mul_Ovf;
3600 else if (!IsFloat (l))
3601 opcode = OpCodes.Mul_Ovf_Un;
3603 opcode = OpCodes.Mul;
3605 opcode = OpCodes.Mul;
3609 case Operator.Division:
3611 opcode = OpCodes.Div_Un;
3613 opcode = OpCodes.Div;
3616 case Operator.Modulus:
3618 opcode = OpCodes.Rem_Un;
3620 opcode = OpCodes.Rem;
3623 case Operator.Addition:
3624 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3625 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3626 opcode = OpCodes.Add_Ovf;
3627 else if (!IsFloat (l))
3628 opcode = OpCodes.Add_Ovf_Un;
3630 opcode = OpCodes.Add;
3632 opcode = OpCodes.Add;
3635 case Operator.Subtraction:
3636 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3637 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3638 opcode = OpCodes.Sub_Ovf;
3639 else if (!IsFloat (l))
3640 opcode = OpCodes.Sub_Ovf_Un;
3642 opcode = OpCodes.Sub;
3644 opcode = OpCodes.Sub;
3647 case Operator.RightShift:
3648 if (!(right is IntConstant)) {
3649 ec.EmitInt (GetShiftMask (l));
3650 ec.Emit (OpCodes.And);
3654 opcode = OpCodes.Shr_Un;
3656 opcode = OpCodes.Shr;
3659 case Operator.LeftShift:
3660 if (!(right is IntConstant)) {
3661 ec.EmitInt (GetShiftMask (l));
3662 ec.Emit (OpCodes.And);
3665 opcode = OpCodes.Shl;
3668 case Operator.Equality:
3669 opcode = OpCodes.Ceq;
3672 case Operator.Inequality:
3673 ec.Emit (OpCodes.Ceq);
3676 opcode = OpCodes.Ceq;
3679 case Operator.LessThan:
3681 opcode = OpCodes.Clt_Un;
3683 opcode = OpCodes.Clt;
3686 case Operator.GreaterThan:
3688 opcode = OpCodes.Cgt_Un;
3690 opcode = OpCodes.Cgt;
3693 case Operator.LessThanOrEqual:
3694 if (IsUnsigned (l) || IsFloat (l))
3695 ec.Emit (OpCodes.Cgt_Un);
3697 ec.Emit (OpCodes.Cgt);
3700 opcode = OpCodes.Ceq;
3703 case Operator.GreaterThanOrEqual:
3704 if (IsUnsigned (l) || IsFloat (l))
3705 ec.Emit (OpCodes.Clt_Un);
3707 ec.Emit (OpCodes.Clt);
3711 opcode = OpCodes.Ceq;
3714 case Operator.BitwiseOr:
3715 opcode = OpCodes.Or;
3718 case Operator.BitwiseAnd:
3719 opcode = OpCodes.And;
3722 case Operator.ExclusiveOr:
3723 opcode = OpCodes.Xor;
3727 throw new InternalErrorException (oper.ToString ());
3733 static int GetShiftMask (TypeSpec type)
3735 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3738 static bool IsUnsigned (TypeSpec t)
3740 switch (t.BuiltinType) {
3741 case BuiltinTypeSpec.Type.Char:
3742 case BuiltinTypeSpec.Type.UInt:
3743 case BuiltinTypeSpec.Type.ULong:
3744 case BuiltinTypeSpec.Type.UShort:
3745 case BuiltinTypeSpec.Type.Byte:
3752 static bool IsFloat (TypeSpec t)
3754 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3757 public Expression ResolveOperator (ResolveContext rc)
3759 eclass = ExprClass.Value;
3761 TypeSpec l = left.Type;
3762 TypeSpec r = right.Type;
3764 bool primitives_only = false;
3767 // Handles predefined primitive types
3769 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3770 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3771 if ((oper & Operator.ShiftMask) == 0) {
3772 if (!DoBinaryOperatorPromotion (rc))
3775 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3779 if (l.IsPointer || r.IsPointer)
3780 return ResolveOperatorPointer (rc, l, r);
3783 if ((state & State.UserOperatorsExcluded) == 0) {
3784 expr = ResolveUserOperator (rc, left, right);
3789 bool lenum = l.IsEnum;
3790 bool renum = r.IsEnum;
3791 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3795 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3796 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3801 if ((oper & Operator.BitwiseMask) != 0) {
3802 expr = EmptyCast.Create (expr, type);
3803 enum_conversion = GetEnumResultCast (type);
3805 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3806 expr = OptimizeAndOperation (expr);
3810 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3811 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3814 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3815 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3819 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3822 // We cannot break here there is also Enum + String possible match
3823 // which is not ambiguous with predefined enum operators
3826 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3827 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3831 } else if (l.IsDelegate || r.IsDelegate) {
3835 expr = ResolveOperatorDelegate (rc, l, r);
3837 // TODO: Can this be ambiguous
3845 // Equality operators are more complicated
3847 if ((oper & Operator.EqualityMask) != 0) {
3848 return ResolveEquality (rc, l, r, primitives_only);
3851 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3855 if (primitives_only)
3859 // Lifted operators have lower priority
3861 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3864 static bool IsEnumOrNullableEnum (TypeSpec type)
3866 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3870 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3871 // if 'left' is not an enumeration constant, create one from the type of 'right'
3872 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3875 case Operator.BitwiseOr:
3876 case Operator.BitwiseAnd:
3877 case Operator.ExclusiveOr:
3878 case Operator.Equality:
3879 case Operator.Inequality:
3880 case Operator.LessThan:
3881 case Operator.LessThanOrEqual:
3882 case Operator.GreaterThan:
3883 case Operator.GreaterThanOrEqual:
3884 if (left.Type.IsEnum)
3887 if (left.IsZeroInteger)
3888 return left.Reduce (ec, right.Type);
3892 case Operator.Addition:
3893 case Operator.Subtraction:
3896 case Operator.Multiply:
3897 case Operator.Division:
3898 case Operator.Modulus:
3899 case Operator.LeftShift:
3900 case Operator.RightShift:
3901 if (right.Type.IsEnum || left.Type.IsEnum)
3910 // The `|' operator used on types which were extended is dangerous
3912 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3914 OpcodeCast lcast = left as OpcodeCast;
3915 if (lcast != null) {
3916 if (IsUnsigned (lcast.UnderlyingType))
3920 OpcodeCast rcast = right as OpcodeCast;
3921 if (rcast != null) {
3922 if (IsUnsigned (rcast.UnderlyingType))
3926 if (lcast == null && rcast == null)
3929 // FIXME: consider constants
3931 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3932 ec.Report.Warning (675, 3, loc,
3933 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3934 ltype.GetSignatureForError ());
3937 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3939 return new PredefinedOperator[] {
3941 // Pointer arithmetic:
3943 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3944 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3945 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3946 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3948 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3949 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3950 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3951 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3954 // T* operator + (int y, T* x);
3955 // T* operator + (uint y, T *x);
3956 // T* operator + (long y, T *x);
3957 // T* operator + (ulong y, T *x);
3959 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3960 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3961 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3962 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3965 // long operator - (T* x, T *y)
3967 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3971 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3973 TypeSpec bool_type = types.Bool;
3976 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3977 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3978 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3979 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3980 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3981 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3982 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3984 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3985 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3986 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3987 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3988 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3989 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3990 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3992 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3993 // Remaining string operators are in lifted tables
3995 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3997 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3998 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3999 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
4003 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
4005 var types = module.Compiler.BuiltinTypes;
4008 // Not strictly lifted but need to be in second group otherwise expressions like
4009 // int + null would resolve to +(object, string) instead of +(int?, int?)
4011 var string_operators = new [] {
4012 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
4013 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
4016 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4017 if (nullable == null)
4018 return string_operators;
4020 var bool_type = types.Bool;
4022 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
4023 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4024 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4025 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4026 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4027 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4028 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4029 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4032 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4033 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4034 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4035 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4036 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4037 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4038 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4040 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4041 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4042 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4043 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4044 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4045 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4046 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4048 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4050 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4051 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4052 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4054 string_operators [0],
4055 string_operators [1]
4059 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4061 TypeSpec bool_type = types.Bool;
4064 new PredefinedEqualityOperator (types.String, bool_type),
4065 new PredefinedEqualityOperator (types.Delegate, bool_type),
4066 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4067 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4068 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4069 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4070 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4071 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4072 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4073 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4077 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4079 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4081 if (nullable == null)
4082 return new PredefinedOperator [0];
4084 var types = module.Compiler.BuiltinTypes;
4085 var bool_type = types.Bool;
4086 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4087 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4088 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4089 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4090 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4091 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4092 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4093 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4096 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4097 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4098 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4099 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4100 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4101 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4102 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4103 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4108 // 7.2.6.2 Binary numeric promotions
4110 bool DoBinaryOperatorPromotion (ResolveContext rc)
4112 TypeSpec ltype = left.Type;
4113 if (ltype.IsNullableType) {
4114 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4118 // This is numeric promotion code only
4120 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4123 TypeSpec rtype = right.Type;
4124 if (rtype.IsNullableType) {
4125 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4128 var lb = ltype.BuiltinType;
4129 var rb = rtype.BuiltinType;
4133 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4134 type = rc.BuiltinTypes.Decimal;
4135 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4136 type = rc.BuiltinTypes.Double;
4137 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4138 type = rc.BuiltinTypes.Float;
4139 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4140 type = rc.BuiltinTypes.ULong;
4142 if (IsSignedType (lb)) {
4143 expr = ConvertSignedConstant (left, type);
4147 } else if (IsSignedType (rb)) {
4148 expr = ConvertSignedConstant (right, type);
4154 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4155 type = rc.BuiltinTypes.Long;
4156 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4157 type = rc.BuiltinTypes.UInt;
4159 if (IsSignedType (lb)) {
4160 expr = ConvertSignedConstant (left, type);
4162 type = rc.BuiltinTypes.Long;
4163 } else if (IsSignedType (rb)) {
4164 expr = ConvertSignedConstant (right, type);
4166 type = rc.BuiltinTypes.Long;
4169 type = rc.BuiltinTypes.Int;
4172 if (ltype != type) {
4173 expr = PromoteExpression (rc, left, type);
4180 if (rtype != type) {
4181 expr = PromoteExpression (rc, right, type);
4191 static bool IsSignedType (BuiltinTypeSpec.Type type)
4194 case BuiltinTypeSpec.Type.Int:
4195 case BuiltinTypeSpec.Type.Short:
4196 case BuiltinTypeSpec.Type.SByte:
4197 case BuiltinTypeSpec.Type.Long:
4204 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4206 var c = expr as Constant;
4210 return c.ConvertImplicitly (type);
4213 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4215 if (expr.Type.IsNullableType) {
4216 return Convert.ImplicitConversionStandard (rc, expr,
4217 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4220 var c = expr as Constant;
4222 return c.ConvertImplicitly (type);
4224 return Convert.ImplicitNumericConversion (expr, type);
4227 protected override Expression DoResolve (ResolveContext ec)
4232 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4233 left = ((ParenthesizedExpression) left).Expr;
4234 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4238 if (left.eclass == ExprClass.Type) {
4239 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4243 left = left.Resolve (ec);
4248 right = right.Resolve (ec);
4252 Constant lc = left as Constant;
4253 Constant rc = right as Constant;
4255 // The conversion rules are ignored in enum context but why
4256 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4257 lc = EnumLiftUp (ec, lc, rc);
4259 rc = EnumLiftUp (ec, rc, lc);
4262 if (rc != null && lc != null) {
4263 int prev_e = ec.Report.Errors;
4264 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4265 if (e != null || ec.Report.Errors != prev_e)
4269 // Comparison warnings
4270 if ((oper & Operator.ComparisonMask) != 0) {
4271 if (left.Equals (right)) {
4272 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4274 CheckOutOfRangeComparison (ec, lc, right.Type);
4275 CheckOutOfRangeComparison (ec, rc, left.Type);
4278 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4279 return DoResolveDynamic (ec);
4281 return DoResolveCore (ec, left, right);
4284 Expression DoResolveDynamic (ResolveContext rc)
4287 var rt = right.Type;
4288 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4289 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4290 Error_OperatorCannotBeApplied (rc, left, right);
4297 // Special handling for logical boolean operators which require rhs not to be
4298 // evaluated based on lhs value
4300 if ((oper & Operator.LogicalMask) != 0) {
4301 Expression cond_left, cond_right, expr;
4303 args = new Arguments (2);
4305 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4306 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4308 var cond_args = new Arguments (1);
4309 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4312 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4313 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4315 left = temp.CreateReferenceExpression (rc, loc);
4316 if (oper == Operator.LogicalAnd) {
4317 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4320 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4324 args.Add (new Argument (left));
4325 args.Add (new Argument (right));
4326 cond_right = new DynamicExpressionStatement (this, args, loc);
4328 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4330 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4331 rc.Report.Error (7083, left.Location,
4332 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4333 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4337 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4338 args.Add (new Argument (right));
4339 right = new DynamicExpressionStatement (this, args, loc);
4342 // bool && dynamic => (temp = left) ? temp && right : temp;
4343 // bool || dynamic => (temp = left) ? temp : temp || right;
4345 if (oper == Operator.LogicalAnd) {
4347 cond_right = temp.CreateReferenceExpression (rc, loc);
4349 cond_left = temp.CreateReferenceExpression (rc, loc);
4353 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4356 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4359 args = new Arguments (2);
4360 args.Add (new Argument (left));
4361 args.Add (new Argument (right));
4362 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4365 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4367 Expression expr = ResolveOperator (ec);
4369 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4371 if (left == null || right == null)
4372 throw new InternalErrorException ("Invalid conversion");
4374 if (oper == Operator.BitwiseOr)
4375 CheckBitwiseOrOnSignExtended (ec);
4380 public override SLE.Expression MakeExpression (BuilderContext ctx)
4382 return MakeExpression (ctx, left, right);
4385 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4387 var le = left.MakeExpression (ctx);
4388 var re = right.MakeExpression (ctx);
4389 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4392 case Operator.Addition:
4393 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4394 case Operator.BitwiseAnd:
4395 return SLE.Expression.And (le, re);
4396 case Operator.BitwiseOr:
4397 return SLE.Expression.Or (le, re);
4398 case Operator.Division:
4399 return SLE.Expression.Divide (le, re);
4400 case Operator.Equality:
4401 return SLE.Expression.Equal (le, re);
4402 case Operator.ExclusiveOr:
4403 return SLE.Expression.ExclusiveOr (le, re);
4404 case Operator.GreaterThan:
4405 return SLE.Expression.GreaterThan (le, re);
4406 case Operator.GreaterThanOrEqual:
4407 return SLE.Expression.GreaterThanOrEqual (le, re);
4408 case Operator.Inequality:
4409 return SLE.Expression.NotEqual (le, re);
4410 case Operator.LeftShift:
4411 return SLE.Expression.LeftShift (le, re);
4412 case Operator.LessThan:
4413 return SLE.Expression.LessThan (le, re);
4414 case Operator.LessThanOrEqual:
4415 return SLE.Expression.LessThanOrEqual (le, re);
4416 case Operator.LogicalAnd:
4417 return SLE.Expression.AndAlso (le, re);
4418 case Operator.LogicalOr:
4419 return SLE.Expression.OrElse (le, re);
4420 case Operator.Modulus:
4421 return SLE.Expression.Modulo (le, re);
4422 case Operator.Multiply:
4423 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4424 case Operator.RightShift:
4425 return SLE.Expression.RightShift (le, re);
4426 case Operator.Subtraction:
4427 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4429 throw new NotImplementedException (oper.ToString ());
4434 // D operator + (D x, D y)
4435 // D operator - (D x, D y)
4437 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4439 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4441 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4442 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4447 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4448 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4458 MethodSpec method = null;
4459 Arguments args = new Arguments (2);
4460 args.Add (new Argument (left));
4461 args.Add (new Argument (right));
4463 if (oper == Operator.Addition) {
4464 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4465 } else if (oper == Operator.Subtraction) {
4466 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4470 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4472 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4473 return new ClassCast (expr, l);
4477 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4479 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4482 // bool operator == (E x, E y);
4483 // bool operator != (E x, E y);
4484 // bool operator < (E x, E y);
4485 // bool operator > (E x, E y);
4486 // bool operator <= (E x, E y);
4487 // bool operator >= (E x, E y);
4489 // E operator & (E x, E y);
4490 // E operator | (E x, E y);
4491 // E operator ^ (E x, E y);
4494 if ((oper & Operator.ComparisonMask) != 0) {
4495 type = rc.BuiltinTypes.Bool;
4501 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4507 if (ltype == rtype) {
4511 var lifted = new Nullable.LiftedBinaryOperator (this);
4513 lifted.Right = right;
4514 return lifted.Resolve (rc);
4517 if (renum && !ltype.IsNullableType) {
4518 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4523 } else if (lenum && !rtype.IsNullableType) {
4524 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4532 // Now try lifted version of predefined operator
4534 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4535 if (nullable_type != null) {
4536 if (renum && !ltype.IsNullableType) {
4537 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4539 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4542 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4545 if ((oper & Operator.BitwiseMask) != 0)
4549 if ((oper & Operator.BitwiseMask) != 0)
4550 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4552 return CreateLiftedValueTypeResult (rc, rtype);
4556 var lifted = new Nullable.LiftedBinaryOperator (this);
4558 lifted.Right = right;
4559 return lifted.Resolve (rc);
4561 } else if (lenum && !rtype.IsNullableType) {
4562 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4564 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4567 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4570 if ((oper & Operator.BitwiseMask) != 0)
4574 if ((oper & Operator.BitwiseMask) != 0)
4575 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4577 return CreateLiftedValueTypeResult (rc, ltype);
4581 var lifted = new Nullable.LiftedBinaryOperator (this);
4583 lifted.Right = expr;
4584 return lifted.Resolve (rc);
4586 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4587 Nullable.Unwrap unwrap = null;
4588 if (left.IsNull || right.IsNull) {
4589 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4590 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4592 if ((oper & Operator.RelationalMask) != 0)
4593 return CreateLiftedValueTypeResult (rc, rtype);
4595 if ((oper & Operator.BitwiseMask) != 0)
4596 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4599 return CreateLiftedValueTypeResult (rc, left.Type);
4601 // Equality operators are valid between E? and null
4603 unwrap = new Nullable.Unwrap (right);
4605 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4609 if ((oper & Operator.BitwiseMask) != 0)
4614 var lifted = new Nullable.LiftedBinaryOperator (this);
4616 lifted.Right = right;
4617 lifted.UnwrapRight = unwrap;
4618 return lifted.Resolve (rc);
4620 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4621 Nullable.Unwrap unwrap = null;
4622 if (right.IsNull || left.IsNull) {
4623 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4624 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4626 if ((oper & Operator.RelationalMask) != 0)
4627 return CreateLiftedValueTypeResult (rc, ltype);
4629 if ((oper & Operator.BitwiseMask) != 0)
4630 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4633 return CreateLiftedValueTypeResult (rc, right.Type);
4635 // Equality operators are valid between E? and null
4637 unwrap = new Nullable.Unwrap (left);
4639 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4643 if ((oper & Operator.BitwiseMask) != 0)
4648 var lifted = new Nullable.LiftedBinaryOperator (this);
4650 lifted.UnwrapLeft = unwrap;
4651 lifted.Right = expr;
4652 return lifted.Resolve (rc);
4660 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4662 TypeSpec underlying_type;
4663 if (expr.Type.IsNullableType) {
4664 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4666 underlying_type = EnumSpec.GetUnderlyingType (nt);
4668 underlying_type = nt;
4669 } else if (expr.Type.IsEnum) {
4670 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4672 underlying_type = expr.Type;
4675 switch (underlying_type.BuiltinType) {
4676 case BuiltinTypeSpec.Type.SByte:
4677 case BuiltinTypeSpec.Type.Byte:
4678 case BuiltinTypeSpec.Type.Short:
4679 case BuiltinTypeSpec.Type.UShort:
4680 underlying_type = rc.BuiltinTypes.Int;
4684 if (expr.Type.IsNullableType || liftType)
4685 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4687 if (expr.Type == underlying_type)
4690 return EmptyCast.Create (expr, underlying_type);
4693 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4696 // U operator - (E e, E f)
4697 // E operator - (E e, U x) // Internal decomposition operator
4698 // E operator - (U x, E e) // Internal decomposition operator
4700 // E operator + (E e, U x)
4701 // E operator + (U x, E e)
4710 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4716 if (!enum_type.IsNullableType) {
4717 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4719 if (oper == Operator.Subtraction)
4720 expr = ConvertEnumSubtractionResult (rc, expr);
4722 expr = ConvertEnumAdditionalResult (expr, enum_type);
4724 enum_conversion = GetEnumResultCast (expr.Type);
4729 var nullable = rc.Module.PredefinedTypes.Nullable;
4732 // Don't try nullable version when nullable type is undefined
4734 if (!nullable.IsDefined)
4737 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4740 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4742 if (oper == Operator.Subtraction)
4743 expr = ConvertEnumSubtractionResult (rc, expr);
4745 expr = ConvertEnumAdditionalResult (expr, enum_type);
4747 enum_conversion = GetEnumResultCast (expr.Type);
4753 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4755 return EmptyCast.Create (expr, enumType);
4758 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4761 // Enumeration subtraction has different result type based on
4764 TypeSpec result_type;
4765 if (left.Type == right.Type) {
4766 var c = right as EnumConstant;
4767 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4769 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4770 // E which is not what expressions E - 1 or 0 - E return
4772 result_type = left.Type;
4774 result_type = left.Type.IsNullableType ?
4775 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4776 EnumSpec.GetUnderlyingType (left.Type);
4779 if (IsEnumOrNullableEnum (left.Type)) {
4780 result_type = left.Type;
4782 result_type = right.Type;
4785 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4786 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4789 return EmptyCast.Create (expr, result_type);
4792 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4794 if (type.IsNullableType)
4795 type = Nullable.NullableInfo.GetUnderlyingType (type);
4798 type = EnumSpec.GetUnderlyingType (type);
4800 switch (type.BuiltinType) {
4801 case BuiltinTypeSpec.Type.SByte:
4802 return ConvCast.Mode.I4_I1;
4803 case BuiltinTypeSpec.Type.Byte:
4804 return ConvCast.Mode.I4_U1;
4805 case BuiltinTypeSpec.Type.Short:
4806 return ConvCast.Mode.I4_I2;
4807 case BuiltinTypeSpec.Type.UShort:
4808 return ConvCast.Mode.I4_U2;
4815 // Equality operators rules
4817 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4820 type = ec.BuiltinTypes.Bool;
4821 bool no_arg_conv = false;
4823 if (!primitives_only) {
4826 // a, Both operands are reference-type values or the value null
4827 // b, One operand is a value of type T where T is a type-parameter and
4828 // the other operand is the value null. Furthermore T does not have the
4829 // value type constraint
4831 // LAMESPEC: Very confusing details in the specification, basically any
4832 // reference like type-parameter is allowed
4834 var tparam_l = l as TypeParameterSpec;
4835 var tparam_r = r as TypeParameterSpec;
4836 if (tparam_l != null) {
4837 if (right is NullLiteral) {
4838 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4841 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4845 if (!tparam_l.IsReferenceType)
4848 l = tparam_l.GetEffectiveBase ();
4849 left = new BoxedCast (left, l);
4850 } else if (left is NullLiteral && tparam_r == null) {
4851 if (TypeSpec.IsReferenceType (r))
4854 if (r.Kind == MemberKind.InternalCompilerType)
4858 if (tparam_r != null) {
4859 if (left is NullLiteral) {
4860 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4863 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4867 if (!tparam_r.IsReferenceType)
4870 r = tparam_r.GetEffectiveBase ();
4871 right = new BoxedCast (right, r);
4872 } else if (right is NullLiteral) {
4873 if (TypeSpec.IsReferenceType (l))
4876 if (l.Kind == MemberKind.InternalCompilerType)
4881 // LAMESPEC: method groups can be compared when they convert to other side delegate
4884 if (right.eclass == ExprClass.MethodGroup) {
4885 result = Convert.ImplicitConversion (ec, right, l, loc);
4891 } else if (r.IsDelegate && l != r) {
4894 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4895 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4902 no_arg_conv = l == r && !l.IsStruct;
4907 // bool operator != (string a, string b)
4908 // bool operator == (string a, string b)
4910 // bool operator != (Delegate a, Delegate b)
4911 // bool operator == (Delegate a, Delegate b)
4913 // bool operator != (bool a, bool b)
4914 // bool operator == (bool a, bool b)
4916 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4917 // they implement an implicit conversion to any of types above. This does
4918 // not apply when both operands are of same reference type
4920 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4921 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4926 // Now try lifted version of predefined operators
4928 if (no_arg_conv && !l.IsNullableType) {
4930 // Optimizes cases which won't match
4933 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4939 // The == and != operators permit one operand to be a value of a nullable
4940 // type and the other to be the null literal, even if no predefined or user-defined
4941 // operator (in unlifted or lifted form) exists for the operation.
4943 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4944 var lifted = new Nullable.LiftedBinaryOperator (this);
4946 lifted.Right = right;
4947 return lifted.Resolve (ec);
4952 // bool operator != (object a, object b)
4953 // bool operator == (object a, object b)
4955 // An explicit reference conversion exists from the
4956 // type of either operand to the type of the other operand.
4959 // Optimize common path
4961 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4964 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4965 !Convert.ExplicitReferenceConversionExists (r, l))
4968 // Reject allowed explicit conversions like int->object
4969 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4972 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4973 ec.Report.Warning (253, 2, loc,
4974 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4975 l.GetSignatureForError ());
4977 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4978 ec.Report.Warning (252, 2, loc,
4979 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4980 r.GetSignatureForError ());
4986 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4989 // bool operator == (void* x, void* y);
4990 // bool operator != (void* x, void* y);
4991 // bool operator < (void* x, void* y);
4992 // bool operator > (void* x, void* y);
4993 // bool operator <= (void* x, void* y);
4994 // bool operator >= (void* x, void* y);
4996 if ((oper & Operator.ComparisonMask) != 0) {
4999 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
5006 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
5012 type = ec.BuiltinTypes.Bool;
5016 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
5020 // Build-in operators method overloading
5022 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
5024 PredefinedOperator best_operator = null;
5025 TypeSpec l = left.Type;
5026 TypeSpec r = right.Type;
5027 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5029 foreach (PredefinedOperator po in operators) {
5030 if ((po.OperatorsMask & oper_mask) == 0)
5033 if (primitives_only) {
5034 if (!po.IsPrimitiveApplicable (l, r))
5037 if (!po.IsApplicable (ec, left, right))
5041 if (best_operator == null) {
5043 if (primitives_only)
5049 best_operator = po.ResolveBetterOperator (ec, best_operator);
5051 if (best_operator == null) {
5052 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5053 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5060 if (best_operator == null)
5063 return best_operator.ConvertResult (ec, this);
5067 // Optimize & constant expressions with 0 value
5069 Expression OptimizeAndOperation (Expression expr)
5071 Constant rc = right as Constant;
5072 Constant lc = left as Constant;
5073 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5075 // The result is a constant with side-effect
5077 Constant side_effect = rc == null ?
5078 new SideEffectConstant (lc, right, loc) :
5079 new SideEffectConstant (rc, left, loc);
5081 return ReducedExpression.Create (side_effect, expr);
5088 // Value types can be compared with the null literal because of the lifting
5089 // language rules. However the result is always true or false.
5091 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5093 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5094 type = rc.BuiltinTypes.Bool;
5098 // FIXME: Handle side effect constants
5099 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5101 if ((Oper & Operator.EqualityMask) != 0) {
5102 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5103 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5105 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5106 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5113 // Performs user-operator overloading
5115 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5117 Expression oper_expr;
5119 var op = ConvertBinaryToUserOperator (oper);
5121 if (l.IsNullableType)
5122 l = Nullable.NullableInfo.GetUnderlyingType (l);
5124 if (r.IsNullableType)
5125 r = Nullable.NullableInfo.GetUnderlyingType (r);
5127 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5128 IList<MemberSpec> right_operators = null;
5131 right_operators = MemberCache.GetUserOperator (r, op, false);
5132 if (right_operators == null && left_operators == null)
5134 } else if (left_operators == null) {
5138 Arguments args = new Arguments (2);
5139 Argument larg = new Argument (left);
5141 Argument rarg = new Argument (right);
5145 // User-defined operator implementations always take precedence
5146 // over predefined operator implementations
5148 if (left_operators != null && right_operators != null) {
5149 left_operators = CombineUserOperators (left_operators, right_operators);
5150 } else if (right_operators != null) {
5151 left_operators = right_operators;
5154 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5155 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5157 var res = new OverloadResolver (left_operators, restr, loc);
5159 var oper_method = res.ResolveOperator (rc, ref args);
5160 if (oper_method == null) {
5162 // Logical && and || cannot be lifted
5164 if ((oper & Operator.LogicalMask) != 0)
5168 // Apply lifted user operators only for liftable types. Implicit conversion
5169 // to nullable types is not allowed
5171 if (!IsLiftedOperatorApplicable ())
5174 // TODO: Cache the result in module container
5175 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5176 if (lifted_methods == null)
5179 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5181 oper_method = res.ResolveOperator (rc, ref args);
5182 if (oper_method == null)
5185 MethodSpec best_original = null;
5186 foreach (MethodSpec ms in left_operators) {
5187 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5193 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5195 // Expression trees use lifted notation in this case
5197 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5198 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5201 var ptypes = best_original.Parameters.Types;
5203 if (left.IsNull || right.IsNull) {
5205 // The lifted operator produces a null value if one or both operands are null
5207 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5208 type = oper_method.ReturnType;
5209 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5213 // The lifted operator produces the value false if one or both operands are null for
5214 // relational operators.
5216 if ((oper & Operator.RelationalMask) != 0) {
5218 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5219 // because return type is actually bool
5221 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5224 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5225 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5229 type = oper_method.ReturnType;
5230 var lifted = new Nullable.LiftedBinaryOperator (this);
5231 lifted.UserOperator = best_original;
5233 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5234 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5237 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5238 lifted.UnwrapRight = new Nullable.Unwrap (right);
5241 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5242 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5244 return lifted.Resolve (rc);
5247 if ((oper & Operator.LogicalMask) != 0) {
5248 // TODO: CreateExpressionTree is allocated every time
5249 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5250 oper == Operator.LogicalAnd, loc).Resolve (rc);
5252 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5255 this.left = larg.Expr;
5256 this.right = rarg.Expr;
5261 bool IsLiftedOperatorApplicable ()
5263 if (left.Type.IsNullableType) {
5264 if ((oper & Operator.EqualityMask) != 0)
5265 return !right.IsNull;
5270 if (right.Type.IsNullableType) {
5271 if ((oper & Operator.EqualityMask) != 0)
5272 return !left.IsNull;
5277 if (TypeSpec.IsValueType (left.Type))
5278 return right.IsNull;
5280 if (TypeSpec.IsValueType (right.Type))
5286 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5288 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5289 if (nullable_type == null)
5293 // Lifted operators permit predefined and user-defined operators that operate
5294 // on non-nullable value types to also be used with nullable forms of those types.
5295 // Lifted operators are constructed from predefined and user-defined operators
5296 // that meet certain requirements
5298 List<MemberSpec> lifted = null;
5299 foreach (MethodSpec oper in operators) {
5301 if ((Oper & Operator.ComparisonMask) != 0) {
5303 // Result type must be of type bool for lifted comparison operators
5305 rt = oper.ReturnType;
5306 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5309 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5315 var ptypes = oper.Parameters.Types;
5316 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5320 // LAMESPEC: I am not sure why but for equality operators to be lifted
5321 // both types have to match
5323 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5327 lifted = new List<MemberSpec> ();
5330 // The lifted form is constructed by adding a single ? modifier to each operand and
5331 // result type except for comparison operators where return type is bool
5334 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5336 var parameters = ParametersCompiled.CreateFullyResolved (
5337 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5338 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5340 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5341 rt, parameters, oper.Modifiers);
5343 lifted.Add (lifted_op);
5350 // Merge two sets of user operators into one, they are mostly distinguish
5351 // except when they share base type and it contains an operator
5353 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5355 var combined = new List<MemberSpec> (left.Count + right.Count);
5356 combined.AddRange (left);
5357 foreach (var r in right) {
5359 foreach (var l in left) {
5360 if (l.DeclaringType == r.DeclaringType) {
5373 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5375 if (c is IntegralConstant || c is CharConstant) {
5377 c.ConvertExplicitly (true, type);
5378 } catch (OverflowException) {
5379 ec.Report.Warning (652, 2, loc,
5380 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5381 type.GetSignatureForError ());
5387 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5388 /// context of a conditional bool expression. This function will return
5389 /// false if it is was possible to use EmitBranchable, or true if it was.
5391 /// The expression's code is generated, and we will generate a branch to `target'
5392 /// if the resulting expression value is equal to isTrue
5394 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5396 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5397 left = left.EmitToField (ec);
5399 if ((oper & Operator.LogicalMask) == 0) {
5400 right = right.EmitToField (ec);
5405 // This is more complicated than it looks, but its just to avoid
5406 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5407 // but on top of that we want for == and != to use a special path
5408 // if we are comparing against null
5410 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5411 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5414 // put the constant on the rhs, for simplicity
5416 if (left is Constant) {
5417 Expression swap = right;
5423 // brtrue/brfalse works with native int only
5425 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5426 left.EmitBranchable (ec, target, my_on_true);
5429 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5430 // right is a boolean, and it's not 'false' => it is 'true'
5431 left.EmitBranchable (ec, target, !my_on_true);
5435 } else if (oper == Operator.LogicalAnd) {
5438 Label tests_end = ec.DefineLabel ();
5440 left.EmitBranchable (ec, tests_end, false);
5441 right.EmitBranchable (ec, target, true);
5442 ec.MarkLabel (tests_end);
5445 // This optimizes code like this
5446 // if (true && i > 4)
5448 if (!(left is Constant))
5449 left.EmitBranchable (ec, target, false);
5451 if (!(right is Constant))
5452 right.EmitBranchable (ec, target, false);
5457 } else if (oper == Operator.LogicalOr){
5459 left.EmitBranchable (ec, target, true);
5460 right.EmitBranchable (ec, target, true);
5463 Label tests_end = ec.DefineLabel ();
5464 left.EmitBranchable (ec, tests_end, true);
5465 right.EmitBranchable (ec, target, false);
5466 ec.MarkLabel (tests_end);
5471 } else if ((oper & Operator.ComparisonMask) == 0) {
5472 base.EmitBranchable (ec, target, on_true);
5479 TypeSpec t = left.Type;
5480 bool is_float = IsFloat (t);
5481 bool is_unsigned = is_float || IsUnsigned (t);
5484 case Operator.Equality:
5486 ec.Emit (OpCodes.Beq, target);
5488 ec.Emit (OpCodes.Bne_Un, target);
5491 case Operator.Inequality:
5493 ec.Emit (OpCodes.Bne_Un, target);
5495 ec.Emit (OpCodes.Beq, target);
5498 case Operator.LessThan:
5500 if (is_unsigned && !is_float)
5501 ec.Emit (OpCodes.Blt_Un, target);
5503 ec.Emit (OpCodes.Blt, target);
5506 ec.Emit (OpCodes.Bge_Un, target);
5508 ec.Emit (OpCodes.Bge, target);
5511 case Operator.GreaterThan:
5513 if (is_unsigned && !is_float)
5514 ec.Emit (OpCodes.Bgt_Un, target);
5516 ec.Emit (OpCodes.Bgt, target);
5519 ec.Emit (OpCodes.Ble_Un, target);
5521 ec.Emit (OpCodes.Ble, target);
5524 case Operator.LessThanOrEqual:
5526 if (is_unsigned && !is_float)
5527 ec.Emit (OpCodes.Ble_Un, target);
5529 ec.Emit (OpCodes.Ble, target);
5532 ec.Emit (OpCodes.Bgt_Un, target);
5534 ec.Emit (OpCodes.Bgt, target);
5538 case Operator.GreaterThanOrEqual:
5540 if (is_unsigned && !is_float)
5541 ec.Emit (OpCodes.Bge_Un, target);
5543 ec.Emit (OpCodes.Bge, target);
5546 ec.Emit (OpCodes.Blt_Un, target);
5548 ec.Emit (OpCodes.Blt, target);
5551 throw new InternalErrorException (oper.ToString ());
5555 public override void Emit (EmitContext ec)
5557 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5558 left = left.EmitToField (ec);
5560 if ((oper & Operator.LogicalMask) == 0) {
5561 right = right.EmitToField (ec);
5566 // Handle short-circuit operators differently
5569 if ((oper & Operator.LogicalMask) != 0) {
5570 Label load_result = ec.DefineLabel ();
5571 Label end = ec.DefineLabel ();
5573 bool is_or = oper == Operator.LogicalOr;
5574 left.EmitBranchable (ec, load_result, is_or);
5576 ec.Emit (OpCodes.Br_S, end);
5578 ec.MarkLabel (load_result);
5579 ec.EmitInt (is_or ? 1 : 0);
5585 // Optimize zero-based operations which cannot be optimized at expression level
5587 if (oper == Operator.Subtraction) {
5588 var lc = left as IntegralConstant;
5589 if (lc != null && lc.IsDefaultValue) {
5591 ec.Emit (OpCodes.Neg);
5596 EmitOperator (ec, left, right);
5599 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5604 EmitOperatorOpcode (ec, oper, left.Type, right);
5607 // Emit result enumerable conversion this way because it's quite complicated get it
5608 // to resolved tree because expression tree cannot see it.
5610 if (enum_conversion != 0)
5611 ConvCast.Emit (ec, enum_conversion);
5614 public override void EmitSideEffect (EmitContext ec)
5616 if ((oper & Operator.LogicalMask) != 0 ||
5617 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5618 base.EmitSideEffect (ec);
5620 left.EmitSideEffect (ec);
5621 right.EmitSideEffect (ec);
5625 public override Expression EmitToField (EmitContext ec)
5627 if ((oper & Operator.LogicalMask) == 0) {
5628 var await_expr = left as Await;
5629 if (await_expr != null && right.IsSideEffectFree) {
5630 await_expr.Statement.EmitPrologue (ec);
5631 left = await_expr.Statement.GetResultExpression (ec);
5635 await_expr = right as Await;
5636 if (await_expr != null && left.IsSideEffectFree) {
5637 await_expr.Statement.EmitPrologue (ec);
5638 right = await_expr.Statement.GetResultExpression (ec);
5643 return base.EmitToField (ec);
5646 protected override void CloneTo (CloneContext clonectx, Expression t)
5648 Binary target = (Binary) t;
5650 target.left = left.Clone (clonectx);
5651 target.right = right.Clone (clonectx);
5654 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5656 Arguments binder_args = new Arguments (4);
5658 MemberAccess sle = new MemberAccess (new MemberAccess (
5659 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5661 CSharpBinderFlags flags = 0;
5662 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5663 flags = CSharpBinderFlags.CheckedContext;
5665 if ((oper & Operator.LogicalMask) != 0)
5666 flags |= CSharpBinderFlags.BinaryOperationLogical;
5668 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5669 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5670 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5671 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5673 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5676 public override Expression CreateExpressionTree (ResolveContext ec)
5678 return CreateExpressionTree (ec, null);
5681 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5684 bool lift_arg = false;
5687 case Operator.Addition:
5688 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5689 method_name = "AddChecked";
5691 method_name = "Add";
5693 case Operator.BitwiseAnd:
5694 method_name = "And";
5696 case Operator.BitwiseOr:
5699 case Operator.Division:
5700 method_name = "Divide";
5702 case Operator.Equality:
5703 method_name = "Equal";
5706 case Operator.ExclusiveOr:
5707 method_name = "ExclusiveOr";
5709 case Operator.GreaterThan:
5710 method_name = "GreaterThan";
5713 case Operator.GreaterThanOrEqual:
5714 method_name = "GreaterThanOrEqual";
5717 case Operator.Inequality:
5718 method_name = "NotEqual";
5721 case Operator.LeftShift:
5722 method_name = "LeftShift";
5724 case Operator.LessThan:
5725 method_name = "LessThan";
5728 case Operator.LessThanOrEqual:
5729 method_name = "LessThanOrEqual";
5732 case Operator.LogicalAnd:
5733 method_name = "AndAlso";
5735 case Operator.LogicalOr:
5736 method_name = "OrElse";
5738 case Operator.Modulus:
5739 method_name = "Modulo";
5741 case Operator.Multiply:
5742 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5743 method_name = "MultiplyChecked";
5745 method_name = "Multiply";
5747 case Operator.RightShift:
5748 method_name = "RightShift";
5750 case Operator.Subtraction:
5751 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5752 method_name = "SubtractChecked";
5754 method_name = "Subtract";
5758 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5761 Arguments args = new Arguments (2);
5762 args.Add (new Argument (left.CreateExpressionTree (ec)));
5763 args.Add (new Argument (right.CreateExpressionTree (ec)));
5764 if (method != null) {
5766 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5768 args.Add (new Argument (method));
5771 return CreateExpressionFactoryCall (ec, method_name, args);
5774 public override object Accept (StructuralVisitor visitor)
5776 return visitor.Visit (this);
5782 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5783 // b, c, d... may be strings or objects.
5785 public class StringConcat : Expression
5787 Arguments arguments;
5789 StringConcat (Location loc)
5792 arguments = new Arguments (2);
5795 public override bool ContainsEmitWithAwait ()
5797 return arguments.ContainsEmitWithAwait ();
5800 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5802 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5803 throw new ArgumentException ();
5805 var s = new StringConcat (loc);
5806 s.type = rc.BuiltinTypes.String;
5807 s.eclass = ExprClass.Value;
5809 s.Append (rc, left);
5810 s.Append (rc, right);
5814 public override Expression CreateExpressionTree (ResolveContext ec)
5816 Argument arg = arguments [0];
5817 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5821 // Creates nested calls tree from an array of arguments used for IL emit
5823 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5825 Arguments concat_args = new Arguments (2);
5826 Arguments add_args = new Arguments (3);
5828 concat_args.Add (left);
5829 add_args.Add (new Argument (left_etree));
5831 concat_args.Add (arguments [pos]);
5832 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5834 var methods = GetConcatMethodCandidates ();
5835 if (methods == null)
5838 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5839 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5843 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5845 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5846 if (++pos == arguments.Count)
5849 left = new Argument (new EmptyExpression (method.ReturnType));
5850 return CreateExpressionAddCall (ec, left, expr, pos);
5853 protected override Expression DoResolve (ResolveContext ec)
5858 void Append (ResolveContext rc, Expression operand)
5863 StringConstant sc = operand as StringConstant;
5865 if (arguments.Count != 0) {
5866 Argument last_argument = arguments [arguments.Count - 1];
5867 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5868 if (last_expr_constant != null) {
5869 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5875 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5877 StringConcat concat_oper = operand as StringConcat;
5878 if (concat_oper != null) {
5879 arguments.AddRange (concat_oper.arguments);
5884 arguments.Add (new Argument (operand));
5887 IList<MemberSpec> GetConcatMethodCandidates ()
5889 return MemberCache.FindMembers (type, "Concat", true);
5892 public override void Emit (EmitContext ec)
5894 // Optimize by removing any extra null arguments, they are no-op
5895 for (int i = 0; i < arguments.Count; ++i) {
5896 if (arguments[i].Expr is NullConstant)
5897 arguments.RemoveAt (i--);
5900 var members = GetConcatMethodCandidates ();
5901 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5902 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5903 if (method != null) {
5904 var call = new CallEmitter ();
5905 call.EmitPredefined (ec, method, arguments, false);
5909 public override void FlowAnalysis (FlowAnalysisContext fc)
5911 arguments.FlowAnalysis (fc);
5914 public override SLE.Expression MakeExpression (BuilderContext ctx)
5916 if (arguments.Count != 2)
5917 throw new NotImplementedException ("arguments.Count != 2");
5919 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5920 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5925 // User-defined conditional logical operator
5927 public class ConditionalLogicalOperator : UserOperatorCall
5929 readonly bool is_and;
5930 Expression oper_expr;
5932 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5933 : base (oper, arguments, expr_tree, loc)
5935 this.is_and = is_and;
5936 eclass = ExprClass.Unresolved;
5939 protected override Expression DoResolve (ResolveContext ec)
5941 AParametersCollection pd = oper.Parameters;
5942 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5943 ec.Report.Error (217, loc,
5944 "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",
5945 oper.GetSignatureForError ());
5949 Expression left_dup = new EmptyExpression (type);
5950 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5951 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5952 if (op_true == null || op_false == null) {
5953 ec.Report.Error (218, loc,
5954 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5955 type.GetSignatureForError (), oper.GetSignatureForError ());
5959 oper_expr = is_and ? op_false : op_true;
5960 eclass = ExprClass.Value;
5964 public override void Emit (EmitContext ec)
5966 Label end_target = ec.DefineLabel ();
5969 // Emit and duplicate left argument
5971 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5972 if (right_contains_await) {
5973 arguments[0] = arguments[0].EmitToField (ec, false);
5974 arguments[0].Expr.Emit (ec);
5976 arguments[0].Expr.Emit (ec);
5977 ec.Emit (OpCodes.Dup);
5978 arguments.RemoveAt (0);
5981 oper_expr.EmitBranchable (ec, end_target, true);
5985 if (right_contains_await) {
5987 // Special handling when right expression contains await and left argument
5988 // could not be left on stack before logical branch
5990 Label skip_left_load = ec.DefineLabel ();
5991 ec.Emit (OpCodes.Br_S, skip_left_load);
5992 ec.MarkLabel (end_target);
5993 arguments[0].Expr.Emit (ec);
5994 ec.MarkLabel (skip_left_load);
5996 ec.MarkLabel (end_target);
6001 public class PointerArithmetic : Expression {
6002 Expression left, right;
6003 readonly Binary.Operator op;
6006 // We assume that `l' is always a pointer
6008 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
6017 public override bool ContainsEmitWithAwait ()
6019 throw new NotImplementedException ();
6022 public override Expression CreateExpressionTree (ResolveContext ec)
6024 Error_PointerInsideExpressionTree (ec);
6028 protected override Expression DoResolve (ResolveContext ec)
6030 eclass = ExprClass.Variable;
6032 var pc = left.Type as PointerContainer;
6033 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6034 Error_VoidPointerOperation (ec);
6041 public override void Emit (EmitContext ec)
6043 TypeSpec op_type = left.Type;
6045 // It must be either array or fixed buffer
6047 if (TypeManager.HasElementType (op_type)) {
6048 element = TypeManager.GetElementType (op_type);
6050 FieldExpr fe = left as FieldExpr;
6052 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6057 int size = BuiltinTypeSpec.GetSize(element);
6058 TypeSpec rtype = right.Type;
6060 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6062 // handle (pointer - pointer)
6066 ec.Emit (OpCodes.Sub);
6070 ec.Emit (OpCodes.Sizeof, element);
6073 ec.Emit (OpCodes.Div);
6075 ec.Emit (OpCodes.Conv_I8);
6078 // handle + and - on (pointer op int)
6080 Constant left_const = left as Constant;
6081 if (left_const != null) {
6083 // Optimize ((T*)null) pointer operations
6085 if (left_const.IsDefaultValue) {
6086 left = EmptyExpression.Null;
6094 var right_const = right as Constant;
6095 if (right_const != null) {
6097 // Optimize 0-based arithmetic
6099 if (right_const.IsDefaultValue)
6103 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6105 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6107 // TODO: Should be the checks resolve context sensitive?
6108 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6109 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6115 if (right_const == null) {
6116 switch (rtype.BuiltinType) {
6117 case BuiltinTypeSpec.Type.SByte:
6118 case BuiltinTypeSpec.Type.Byte:
6119 case BuiltinTypeSpec.Type.Short:
6120 case BuiltinTypeSpec.Type.UShort:
6121 case BuiltinTypeSpec.Type.Int:
6122 ec.Emit (OpCodes.Conv_I);
6124 case BuiltinTypeSpec.Type.UInt:
6125 ec.Emit (OpCodes.Conv_U);
6130 if (right_const == null && size != 1){
6132 ec.Emit (OpCodes.Sizeof, element);
6135 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6136 ec.Emit (OpCodes.Conv_I8);
6138 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6141 if (left_const == null) {
6142 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6143 ec.Emit (OpCodes.Conv_I);
6144 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6145 ec.Emit (OpCodes.Conv_U);
6147 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6154 // A boolean-expression is an expression that yields a result
6157 public class BooleanExpression : ShimExpression
6159 public BooleanExpression (Expression expr)
6162 this.loc = expr.Location;
6165 public override Expression CreateExpressionTree (ResolveContext ec)
6167 // TODO: We should emit IsTrue (v4) instead of direct user operator
6168 // call but that would break csc compatibility
6169 return base.CreateExpressionTree (ec);
6172 protected override Expression DoResolve (ResolveContext ec)
6174 // A boolean-expression is required to be of a type
6175 // that can be implicitly converted to bool or of
6176 // a type that implements operator true
6178 expr = expr.Resolve (ec);
6182 Assign ass = expr as Assign;
6183 if (ass != null && ass.Source is Constant) {
6184 ec.Report.Warning (665, 3, loc,
6185 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6188 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6191 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6192 Arguments args = new Arguments (1);
6193 args.Add (new Argument (expr));
6194 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6197 type = ec.BuiltinTypes.Bool;
6198 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6199 if (converted != null)
6203 // If no implicit conversion to bool exists, try using `operator true'
6205 converted = GetOperatorTrue (ec, expr, loc);
6206 if (converted == null) {
6207 expr.Error_ValueCannotBeConverted (ec, type, false);
6214 public override object Accept (StructuralVisitor visitor)
6216 return visitor.Visit (this);
6220 public class BooleanExpressionFalse : Unary
6222 public BooleanExpressionFalse (Expression expr)
6223 : base (Operator.LogicalNot, expr, expr.Location)
6227 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6229 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6234 /// Implements the ternary conditional operator (?:)
6236 public class Conditional : Expression {
6237 Expression expr, true_expr, false_expr;
6239 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6242 this.true_expr = true_expr;
6243 this.false_expr = false_expr;
6249 public Expression Expr {
6255 public Expression TrueExpr {
6261 public Expression FalseExpr {
6269 public override bool ContainsEmitWithAwait ()
6271 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6274 public override Expression CreateExpressionTree (ResolveContext ec)
6276 Arguments args = new Arguments (3);
6277 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6278 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6279 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6280 return CreateExpressionFactoryCall (ec, "Condition", args);
6283 protected override Expression DoResolve (ResolveContext ec)
6285 expr = expr.Resolve (ec);
6286 true_expr = true_expr.Resolve (ec);
6287 false_expr = false_expr.Resolve (ec);
6289 if (true_expr == null || false_expr == null || expr == null)
6292 eclass = ExprClass.Value;
6293 TypeSpec true_type = true_expr.Type;
6294 TypeSpec false_type = false_expr.Type;
6298 // First, if an implicit conversion exists from true_expr
6299 // to false_expr, then the result type is of type false_expr.Type
6301 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6302 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6303 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6305 // Check if both can convert implicitly to each other's type
6309 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6310 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6312 // LAMESPEC: There seems to be hardcoded promotition to int type when
6313 // both sides are numeric constants and one side is int constant and
6314 // other side is numeric constant convertible to int.
6316 // var res = condition ? (short)1 : 1;
6318 // Type of res is int even if according to the spec the conversion is
6319 // ambiguous because 1 literal can be converted to short.
6321 if (conv_false_expr != null) {
6322 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6324 conv_false_expr = null;
6325 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6326 conv_false_expr = null;
6330 if (conv_false_expr != null) {
6331 ec.Report.Error (172, true_expr.Location,
6332 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6333 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6338 if (true_expr.Type != type)
6339 true_expr = EmptyCast.Create (true_expr, type);
6340 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6343 if (false_type != InternalType.ErrorType) {
6344 ec.Report.Error (173, true_expr.Location,
6345 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6346 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6352 Constant c = expr as Constant;
6354 bool is_false = c.IsDefaultValue;
6357 // Don't issue the warning for constant expressions
6359 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6360 // CSC: Missing warning
6361 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6364 return ReducedExpression.Create (
6365 is_false ? false_expr : true_expr, this,
6366 false_expr is Constant && true_expr is Constant).Resolve (ec);
6372 public override void Emit (EmitContext ec)
6374 Label false_target = ec.DefineLabel ();
6375 Label end_target = ec.DefineLabel ();
6377 expr.EmitBranchable (ec, false_target, false);
6378 true_expr.Emit (ec);
6381 // Verifier doesn't support interface merging. When there are two types on
6382 // the stack without common type hint and the common type is an interface.
6383 // Use temporary local to give verifier hint on what type to unify the stack
6385 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6386 var temp = ec.GetTemporaryLocal (type);
6387 ec.Emit (OpCodes.Stloc, temp);
6388 ec.Emit (OpCodes.Ldloc, temp);
6389 ec.FreeTemporaryLocal (temp, type);
6392 ec.Emit (OpCodes.Br, end_target);
6393 ec.MarkLabel (false_target);
6394 false_expr.Emit (ec);
6395 ec.MarkLabel (end_target);
6398 public override void FlowAnalysis (FlowAnalysisContext fc)
6400 expr.FlowAnalysisConditional (fc);
6401 var expr_true = fc.DefiniteAssignmentOnTrue;
6402 var expr_false = fc.DefiniteAssignmentOnFalse;
6404 fc.BranchDefiniteAssignment (expr_true);
6405 true_expr.FlowAnalysis (fc);
6406 var true_fc = fc.DefiniteAssignment;
6408 fc.BranchDefiniteAssignment (expr_false);
6409 false_expr.FlowAnalysis (fc);
6411 fc.DefiniteAssignment &= true_fc;
6414 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6416 expr.FlowAnalysisConditional (fc);
6417 var expr_true = fc.DefiniteAssignmentOnTrue;
6418 var expr_false = fc.DefiniteAssignmentOnFalse;
6420 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6421 true_expr.FlowAnalysisConditional (fc);
6422 var true_fc = fc.DefiniteAssignment;
6423 var true_da_true = fc.DefiniteAssignmentOnTrue;
6424 var true_da_false = fc.DefiniteAssignmentOnFalse;
6426 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6427 false_expr.FlowAnalysisConditional (fc);
6429 fc.DefiniteAssignment &= true_fc;
6430 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6431 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6434 protected override void CloneTo (CloneContext clonectx, Expression t)
6436 Conditional target = (Conditional) t;
6438 target.expr = expr.Clone (clonectx);
6439 target.true_expr = true_expr.Clone (clonectx);
6440 target.false_expr = false_expr.Clone (clonectx);
6444 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6446 LocalTemporary temp;
6449 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6450 public abstract void SetHasAddressTaken ();
6452 public abstract bool IsLockedByStatement { get; set; }
6454 public abstract bool IsFixed { get; }
6455 public abstract bool IsRef { get; }
6456 public abstract string Name { get; }
6459 // Variable IL data, it has to be protected to encapsulate hoisted variables
6461 protected abstract ILocalVariable Variable { get; }
6464 // Variable flow-analysis data
6466 public abstract VariableInfo VariableInfo { get; }
6469 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6471 HoistedVariable hv = GetHoistedVariable (ec);
6473 hv.AddressOf (ec, mode);
6477 Variable.EmitAddressOf (ec);
6480 public override bool ContainsEmitWithAwait ()
6485 public override Expression CreateExpressionTree (ResolveContext ec)
6487 HoistedVariable hv = GetHoistedVariable (ec);
6489 return hv.CreateExpressionTree ();
6491 Arguments arg = new Arguments (1);
6492 arg.Add (new Argument (this));
6493 return CreateExpressionFactoryCall (ec, "Constant", arg);
6496 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6498 if (IsLockedByStatement) {
6499 rc.Report.Warning (728, 2, loc,
6500 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6507 public override void Emit (EmitContext ec)
6512 public override void EmitSideEffect (EmitContext ec)
6518 // This method is used by parameters that are references, that are
6519 // being passed as references: we only want to pass the pointer (that
6520 // is already stored in the parameter, not the address of the pointer,
6521 // and not the value of the variable).
6523 public void EmitLoad (EmitContext ec)
6528 public void Emit (EmitContext ec, bool leave_copy)
6530 HoistedVariable hv = GetHoistedVariable (ec);
6532 hv.Emit (ec, leave_copy);
6540 // If we are a reference, we loaded on the stack a pointer
6541 // Now lets load the real value
6543 ec.EmitLoadFromPtr (type);
6547 ec.Emit (OpCodes.Dup);
6550 temp = new LocalTemporary (Type);
6556 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6557 bool prepare_for_load)
6559 HoistedVariable hv = GetHoistedVariable (ec);
6561 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6565 New n_source = source as New;
6566 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6567 if (!n_source.Emit (ec, this)) {
6571 ec.EmitLoadFromPtr (type);
6583 ec.Emit (OpCodes.Dup);
6585 temp = new LocalTemporary (Type);
6591 ec.EmitStoreFromPtr (type);
6593 Variable.EmitAssign (ec);
6601 public override Expression EmitToField (EmitContext ec)
6603 HoistedVariable hv = GetHoistedVariable (ec);
6605 return hv.EmitToField (ec);
6608 return base.EmitToField (ec);
6611 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6613 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6616 public HoistedVariable GetHoistedVariable (EmitContext ec)
6618 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6621 public override string GetSignatureForError ()
6626 public bool IsHoisted {
6627 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6632 // Resolved reference to a local variable
6634 public class LocalVariableReference : VariableReference
6636 public LocalVariable local_info;
6638 public LocalVariableReference (LocalVariable li, Location l)
6640 this.local_info = li;
6644 public override VariableInfo VariableInfo {
6645 get { return local_info.VariableInfo; }
6648 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6650 return local_info.HoistedVariant;
6656 // A local variable is always fixed
6658 public override bool IsFixed {
6664 public override bool IsLockedByStatement {
6666 return local_info.IsLocked;
6669 local_info.IsLocked = value;
6673 public override bool IsRef {
6674 get { return false; }
6677 public override string Name {
6678 get { return local_info.Name; }
6683 public override void FlowAnalysis (FlowAnalysisContext fc)
6685 VariableInfo variable_info = VariableInfo;
6686 if (variable_info == null)
6689 if (fc.IsDefinitelyAssigned (variable_info))
6692 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6693 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6696 public override void SetHasAddressTaken ()
6698 local_info.SetHasAddressTaken ();
6701 void DoResolveBase (ResolveContext ec)
6703 eclass = ExprClass.Variable;
6704 type = local_info.Type;
6707 // If we are referencing a variable from the external block
6708 // flag it for capturing
6710 if (ec.MustCaptureVariable (local_info)) {
6711 if (local_info.AddressTaken) {
6712 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6713 } else if (local_info.IsFixed) {
6714 ec.Report.Error (1764, loc,
6715 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6716 GetSignatureForError ());
6719 if (ec.IsVariableCapturingRequired) {
6720 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6721 storey.CaptureLocalVariable (ec, local_info);
6726 protected override Expression DoResolve (ResolveContext ec)
6728 local_info.SetIsUsed ();
6732 if (local_info.Type == InternalType.VarOutType) {
6733 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6734 GetSignatureForError ());
6736 type = InternalType.ErrorType;
6742 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6745 // Don't be too pedantic when variable is used as out param or for some broken code
6746 // which uses property/indexer access to run some initialization
6748 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6749 local_info.SetIsUsed ();
6751 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6752 if (rhs == EmptyExpression.LValueMemberAccess) {
6753 // CS1654 already reported
6757 if (rhs == EmptyExpression.OutAccess) {
6758 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6759 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6760 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6761 } else if (rhs == EmptyExpression.UnaryAddress) {
6762 code = 459; msg = "Cannot take the address of {1} `{0}'";
6764 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6766 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6770 if (eclass == ExprClass.Unresolved)
6773 return base.DoResolveLValue (ec, rhs);
6776 public override int GetHashCode ()
6778 return local_info.GetHashCode ();
6781 public override bool Equals (object obj)
6783 LocalVariableReference lvr = obj as LocalVariableReference;
6787 return local_info == lvr.local_info;
6790 protected override ILocalVariable Variable {
6791 get { return local_info; }
6794 public override string ToString ()
6796 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6799 protected override void CloneTo (CloneContext clonectx, Expression t)
6806 /// This represents a reference to a parameter in the intermediate
6809 public class ParameterReference : VariableReference
6811 protected ParametersBlock.ParameterInfo pi;
6813 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6821 public override bool IsLockedByStatement {
6826 pi.IsLocked = value;
6830 public override bool IsRef {
6831 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6834 bool HasOutModifier {
6835 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6838 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6840 return pi.Parameter.HoistedVariant;
6844 // A ref or out parameter is classified as a moveable variable, even
6845 // if the argument given for the parameter is a fixed variable
6847 public override bool IsFixed {
6848 get { return !IsRef; }
6851 public override string Name {
6852 get { return Parameter.Name; }
6855 public Parameter Parameter {
6856 get { return pi.Parameter; }
6859 public override VariableInfo VariableInfo {
6860 get { return pi.VariableInfo; }
6863 protected override ILocalVariable Variable {
6864 get { return Parameter; }
6869 public override void AddressOf (EmitContext ec, AddressOp mode)
6872 // ParameterReferences might already be a reference
6879 base.AddressOf (ec, mode);
6882 public override void SetHasAddressTaken ()
6884 Parameter.HasAddressTaken = true;
6887 bool DoResolveBase (ResolveContext ec)
6889 if (eclass != ExprClass.Unresolved)
6892 type = pi.ParameterType;
6893 eclass = ExprClass.Variable;
6896 // If we are referencing a parameter from the external block
6897 // flag it for capturing
6899 if (ec.MustCaptureVariable (pi)) {
6900 if (Parameter.HasAddressTaken)
6901 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6904 ec.Report.Error (1628, loc,
6905 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6906 Name, ec.CurrentAnonymousMethod.ContainerType);
6909 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6910 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6911 storey.CaptureParameter (ec, pi, this);
6918 public override int GetHashCode ()
6920 return Name.GetHashCode ();
6923 public override bool Equals (object obj)
6925 ParameterReference pr = obj as ParameterReference;
6929 return Name == pr.Name;
6932 protected override void CloneTo (CloneContext clonectx, Expression target)
6938 public override Expression CreateExpressionTree (ResolveContext ec)
6940 HoistedVariable hv = GetHoistedVariable (ec);
6942 return hv.CreateExpressionTree ();
6944 return Parameter.ExpressionTreeVariableReference ();
6947 protected override Expression DoResolve (ResolveContext ec)
6949 if (!DoResolveBase (ec))
6955 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6957 if (!DoResolveBase (ec))
6960 if (Parameter.HoistedVariant != null)
6961 Parameter.HoistedVariant.IsAssigned = true;
6963 return base.DoResolveLValue (ec, right_side);
6966 public override void FlowAnalysis (FlowAnalysisContext fc)
6968 VariableInfo variable_info = VariableInfo;
6969 if (variable_info == null)
6972 if (fc.IsDefinitelyAssigned (variable_info))
6975 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6976 fc.SetVariableAssigned (variable_info);
6981 /// Invocation of methods or delegates.
6983 public class Invocation : ExpressionStatement
6985 public class Predefined : Invocation
6987 public Predefined (MethodGroupExpr expr, Arguments arguments)
6988 : base (expr, arguments)
6993 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6995 mg.BestCandidate.CheckObsoleteness (rc, loc);
7001 protected Arguments arguments;
7002 protected Expression expr;
7003 protected MethodGroupExpr mg;
7004 bool conditional_access_receiver;
7006 public Invocation (Expression expr, Arguments arguments)
7009 this.arguments = arguments;
7011 loc = expr.Location;
7016 public Arguments Arguments {
7022 public Expression Exp {
7028 public MethodGroupExpr MethodGroup {
7034 public override Location StartLocation {
7036 return expr.StartLocation;
7042 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7044 if (MethodGroup == null)
7047 var candidate = MethodGroup.BestCandidate;
7048 if (candidate == null || !(candidate.IsStatic || Exp is This))
7051 var args_count = arguments == null ? 0 : arguments.Count;
7052 if (args_count != body.Parameters.Count)
7055 var lambda_parameters = body.Block.Parameters.FixedParameters;
7056 for (int i = 0; i < args_count; ++i) {
7057 var pr = arguments[i].Expr as ParameterReference;
7061 if (lambda_parameters[i] != pr.Parameter)
7064 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7068 var emg = MethodGroup as ExtensionMethodGroupExpr;
7070 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7071 if (candidate.IsGeneric) {
7072 var targs = new TypeExpression [candidate.Arity];
7073 for (int i = 0; i < targs.Length; ++i) {
7074 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7077 mg.SetTypeArguments (null, new TypeArguments (targs));
7086 protected override void CloneTo (CloneContext clonectx, Expression t)
7088 Invocation target = (Invocation) t;
7090 if (arguments != null)
7091 target.arguments = arguments.Clone (clonectx);
7093 target.expr = expr.Clone (clonectx);
7096 public override bool ContainsEmitWithAwait ()
7098 if (arguments != null && arguments.ContainsEmitWithAwait ())
7101 return mg.ContainsEmitWithAwait ();
7104 public override Expression CreateExpressionTree (ResolveContext ec)
7106 Expression instance = mg.IsInstance ?
7107 mg.InstanceExpression.CreateExpressionTree (ec) :
7108 new NullLiteral (loc);
7110 var args = Arguments.CreateForExpressionTree (ec, arguments,
7112 mg.CreateExpressionTree (ec));
7114 return CreateExpressionFactoryCall (ec, "Call", args);
7117 void ResolveConditionalAccessReceiver (ResolveContext rc)
7119 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7120 conditional_access_receiver = true;
7124 bool statement_resolve;
7125 public override ExpressionStatement ResolveStatement (BlockContext bc)
7127 statement_resolve = true;
7128 var es = base.ResolveStatement (bc);
7129 statement_resolve = false;
7134 protected override Expression DoResolve (ResolveContext rc)
7136 ResolveConditionalAccessReceiver (rc);
7137 return DoResolveInvocation (rc);
7140 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7142 var sn = expr as SimpleName;
7143 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
7144 var targets = new List<Expression> (arguments.Count);
7145 var variables = new List<LocalVariable> (arguments.Count);
7146 foreach (var arg in arguments) {
7147 var arg_sn = arg.Expr as SimpleName;
7148 if (arg_sn == null || arg_sn.Arity != 0) {
7149 rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
7150 return ErrorExpression.Instance;
7153 var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
7154 rc.CurrentBlock.AddLocalName (lv);
7157 targets.Add (new LocalVariableReference (lv, arg_sn.Location));
7160 var res = new TupleDeconstruct (targets, variables, right_side, loc);
7161 return res.Resolve (rc);
7164 return base.DoResolveLValue (rc, right_side);
7167 Expression DoResolveInvocation (ResolveContext ec)
7169 Expression member_expr;
7170 var atn = expr as ATypeNameExpression;
7172 var flags = default (ResolveContext.FlagsHandle);
7173 if (conditional_access_receiver)
7174 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7177 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7178 if (member_expr != null) {
7179 var name_of = member_expr as NameOf;
7180 if (name_of != null) {
7181 return name_of.ResolveOverload (ec, arguments);
7184 member_expr = member_expr.Resolve (ec);
7187 member_expr = expr.Resolve (ec);
7190 if (conditional_access_receiver)
7193 if (member_expr == null)
7197 // Next, evaluate all the expressions in the argument list
7199 bool dynamic_arg = false;
7200 if (arguments != null) {
7201 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7202 arguments.Resolve (ec, out dynamic_arg);
7206 TypeSpec expr_type = member_expr.Type;
7207 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7208 return DoResolveDynamic (ec, member_expr);
7210 mg = member_expr as MethodGroupExpr;
7211 Expression invoke = null;
7214 if (expr_type != null && expr_type.IsDelegate) {
7215 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7216 invoke = invoke.Resolve (ec);
7217 if (invoke == null || !dynamic_arg)
7220 if (member_expr is RuntimeValueExpression) {
7221 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7222 member_expr.Type.GetSignatureForError ());
7226 MemberExpr me = member_expr as MemberExpr;
7228 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7232 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7233 member_expr.GetSignatureForError ());
7238 if (invoke == null) {
7239 mg = DoResolveOverload (ec);
7245 return DoResolveDynamic (ec, member_expr);
7247 var method = mg.BestCandidate;
7248 type = mg.BestCandidateReturnType;
7249 if (conditional_access_receiver && !statement_resolve)
7250 type = LiftMemberType (ec, type);
7252 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7254 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7256 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7260 IsSpecialMethodInvocation (ec, method, loc);
7262 eclass = ExprClass.Value;
7266 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7269 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7271 args = dmb.Arguments;
7272 if (arguments != null)
7273 args.AddRange (arguments);
7274 } else if (mg == null) {
7275 if (arguments == null)
7276 args = new Arguments (1);
7280 args.Insert (0, new Argument (memberExpr));
7284 ec.Report.Error (1971, loc,
7285 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7290 if (arguments == null)
7291 args = new Arguments (1);
7295 MemberAccess ma = expr as MemberAccess;
7297 var inst = mg.InstanceExpression;
7298 var left_type = inst as TypeExpr;
7299 if (left_type != null) {
7300 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7301 } else if (inst != null) {
7303 // Any value type has to be pass as by-ref to get back the same
7304 // instance on which the member was called
7306 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7307 Argument.AType.Ref : Argument.AType.None;
7308 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7310 } else { // is SimpleName
7311 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7312 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7314 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7319 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7322 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7324 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7327 public override void FlowAnalysis (FlowAnalysisContext fc)
7329 if (mg.IsConditionallyExcluded)
7332 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7334 mg.FlowAnalysis (fc);
7336 if (arguments != null)
7337 arguments.FlowAnalysis (fc);
7339 if (conditional_access_receiver)
7340 fc.DefiniteAssignment = da;
7343 public override string GetSignatureForError ()
7345 return mg.GetSignatureForError ();
7348 public override bool HasConditionalAccess ()
7350 return expr.HasConditionalAccess ();
7354 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7355 // or the type dynamic, then the member is invocable
7357 public static bool IsMemberInvocable (MemberSpec member)
7359 switch (member.Kind) {
7360 case MemberKind.Event:
7362 case MemberKind.Field:
7363 case MemberKind.Property:
7364 var m = member as IInterfaceMemberSpec;
7365 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7371 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7373 if (!method.IsReservedMethod)
7376 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7379 ec.Report.SymbolRelatedToPreviousError (method);
7380 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7381 method.GetSignatureForError ());
7386 public override void Emit (EmitContext ec)
7388 if (mg.IsConditionallyExcluded)
7391 if (conditional_access_receiver)
7392 mg.EmitCall (ec, arguments, type, false);
7394 mg.EmitCall (ec, arguments, false);
7397 public override void EmitPrepare (EmitContext ec)
7399 mg.EmitPrepare (ec);
7401 arguments?.EmitPrepare (ec);
7404 public override void EmitStatement (EmitContext ec)
7406 if (mg.IsConditionallyExcluded)
7409 if (conditional_access_receiver)
7410 mg.EmitCall (ec, arguments, type, true);
7412 mg.EmitCall (ec, arguments, true);
7415 public override SLE.Expression MakeExpression (BuilderContext ctx)
7417 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7420 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7423 throw new NotSupportedException ();
7425 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7426 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7430 public override object Accept (StructuralVisitor visitor)
7432 return visitor.Visit (this);
7437 // Implements simple new expression
7439 public class New : ExpressionStatement, IMemoryLocation
7441 protected Arguments arguments;
7444 // During bootstrap, it contains the RequestedType,
7445 // but if `type' is not null, it *might* contain a NewDelegate
7446 // (because of field multi-initialization)
7448 protected Expression RequestedType;
7450 protected MethodSpec method;
7452 public New (Expression requested_type, Arguments arguments, Location l)
7454 RequestedType = requested_type;
7455 this.arguments = arguments;
7460 public Arguments Arguments {
7467 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7469 public bool IsGeneratedStructConstructor {
7471 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7475 public Expression TypeExpression {
7477 return RequestedType;
7484 /// Converts complex core type syntax like 'new int ()' to simple constant
7486 public static Constant Constantify (TypeSpec t, Location loc)
7488 switch (t.BuiltinType) {
7489 case BuiltinTypeSpec.Type.Int:
7490 return new IntConstant (t, 0, loc);
7491 case BuiltinTypeSpec.Type.UInt:
7492 return new UIntConstant (t, 0, loc);
7493 case BuiltinTypeSpec.Type.Long:
7494 return new LongConstant (t, 0, loc);
7495 case BuiltinTypeSpec.Type.ULong:
7496 return new ULongConstant (t, 0, loc);
7497 case BuiltinTypeSpec.Type.Float:
7498 return new FloatConstant (t, 0, loc);
7499 case BuiltinTypeSpec.Type.Double:
7500 return new DoubleConstant (t, 0, loc);
7501 case BuiltinTypeSpec.Type.Short:
7502 return new ShortConstant (t, 0, loc);
7503 case BuiltinTypeSpec.Type.UShort:
7504 return new UShortConstant (t, 0, loc);
7505 case BuiltinTypeSpec.Type.SByte:
7506 return new SByteConstant (t, 0, loc);
7507 case BuiltinTypeSpec.Type.Byte:
7508 return new ByteConstant (t, 0, loc);
7509 case BuiltinTypeSpec.Type.Char:
7510 return new CharConstant (t, '\0', loc);
7511 case BuiltinTypeSpec.Type.Bool:
7512 return new BoolConstant (t, false, loc);
7513 case BuiltinTypeSpec.Type.Decimal:
7514 return new DecimalConstant (t, 0, loc);
7518 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7520 if (t.IsNullableType)
7521 return Nullable.LiftedNull.Create (t, loc);
7526 public override bool ContainsEmitWithAwait ()
7528 return arguments != null && arguments.ContainsEmitWithAwait ();
7532 // Checks whether the type is an interface that has the
7533 // [ComImport, CoClass] attributes and must be treated
7536 public Expression CheckComImport (ResolveContext ec)
7538 if (!type.IsInterface)
7542 // Turn the call into:
7543 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7545 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7546 if (real_class == null)
7549 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7550 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7551 return cast.Resolve (ec);
7554 public override Expression CreateExpressionTree (ResolveContext ec)
7557 if (method == null) {
7558 args = new Arguments (1);
7559 args.Add (new Argument (new TypeOf (type, loc)));
7561 args = Arguments.CreateForExpressionTree (ec,
7562 arguments, new TypeOfMethod (method, loc));
7565 return CreateExpressionFactoryCall (ec, "New", args);
7568 protected override Expression DoResolve (ResolveContext ec)
7570 if (RequestedType is TupleTypeExpr) {
7571 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
7574 type = RequestedType.ResolveAsType (ec);
7578 eclass = ExprClass.Value;
7580 if (type.IsPointer) {
7581 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7582 type.GetSignatureForError ());
7586 if (arguments == null) {
7587 Constant c = Constantify (type, RequestedType.Location);
7589 return ReducedExpression.Create (c, this);
7592 if (type.IsDelegate) {
7593 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7596 var tparam = type as TypeParameterSpec;
7597 if (tparam != null) {
7599 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7600 // where type parameter constraint is inflated to struct
7602 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7603 ec.Report.Error (304, loc,
7604 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7605 type.GetSignatureForError ());
7608 if ((arguments != null) && (arguments.Count != 0)) {
7609 ec.Report.Error (417, loc,
7610 "`{0}': cannot provide arguments when creating an instance of a variable type",
7611 type.GetSignatureForError ());
7617 if (type.IsStatic) {
7618 ec.Report.SymbolRelatedToPreviousError (type);
7619 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7623 if (type.IsInterface || type.IsAbstract){
7624 if (!TypeManager.IsGenericType (type)) {
7625 RequestedType = CheckComImport (ec);
7626 if (RequestedType != null)
7627 return RequestedType;
7630 ec.Report.SymbolRelatedToPreviousError (type);
7631 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7636 if (arguments != null) {
7637 arguments.Resolve (ec, out dynamic);
7642 method = ConstructorLookup (ec, type, ref arguments, loc);
7645 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7646 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7652 void DoEmitTypeParameter (EmitContext ec)
7654 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7658 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7659 ec.Emit (OpCodes.Call, ctor_factory);
7663 // This Emit can be invoked in two contexts:
7664 // * As a mechanism that will leave a value on the stack (new object)
7665 // * As one that wont (init struct)
7667 // If we are dealing with a ValueType, we have a few
7668 // situations to deal with:
7670 // * The target is a ValueType, and we have been provided
7671 // the instance (this is easy, we are being assigned).
7673 // * The target of New is being passed as an argument,
7674 // to a boxing operation or a function that takes a
7677 // In this case, we need to create a temporary variable
7678 // that is the argument of New.
7680 // Returns whether a value is left on the stack
7682 // *** Implementation note ***
7684 // To benefit from this optimization, each assignable expression
7685 // has to manually cast to New and call this Emit.
7687 // TODO: It's worth to implement it for arrays and fields
7689 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7691 bool is_value_type = type.IsStructOrEnum;
7692 VariableReference vr = target as VariableReference;
7694 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7696 if (target != null && is_value_type && (vr != null || method == null)) {
7697 if (prepare_await) {
7698 arguments = arguments.Emit (ec, false, true);
7699 prepare_await = false;
7702 target.AddressOf (ec, AddressOp.Store);
7703 } else if (vr != null && vr.IsRef) {
7707 if (arguments != null) {
7709 arguments = arguments.Emit (ec, false, true);
7711 arguments.Emit (ec);
7714 if (is_value_type) {
7715 if (method == null) {
7716 ec.Emit (OpCodes.Initobj, type);
7721 ec.MarkCallEntry (loc);
7722 ec.Emit (OpCodes.Call, method);
7727 if (type is TypeParameterSpec) {
7728 DoEmitTypeParameter (ec);
7732 ec.MarkCallEntry (loc);
7733 ec.Emit (OpCodes.Newobj, method);
7737 public override void Emit (EmitContext ec)
7739 LocalTemporary v = null;
7740 if (method == null && type.IsStructOrEnum) {
7741 // TODO: Use temporary variable from pool
7742 v = new LocalTemporary (type);
7749 public override void EmitStatement (EmitContext ec)
7751 LocalTemporary v = null;
7752 if (method == null && TypeSpec.IsValueType (type)) {
7753 // TODO: Use temporary variable from pool
7754 v = new LocalTemporary (type);
7758 ec.Emit (OpCodes.Pop);
7761 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7766 public override void FlowAnalysis (FlowAnalysisContext fc)
7768 if (arguments != null)
7769 arguments.FlowAnalysis (fc);
7772 public void AddressOf (EmitContext ec, AddressOp mode)
7774 EmitAddressOf (ec, mode);
7777 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7779 LocalTemporary value_target = new LocalTemporary (type);
7781 if (type is TypeParameterSpec) {
7782 DoEmitTypeParameter (ec);
7783 value_target.Store (ec);
7784 value_target.AddressOf (ec, mode);
7785 return value_target;
7788 value_target.AddressOf (ec, AddressOp.Store);
7790 if (method == null) {
7791 ec.Emit (OpCodes.Initobj, type);
7793 if (arguments != null)
7794 arguments.Emit (ec);
7796 ec.Emit (OpCodes.Call, method);
7799 value_target.AddressOf (ec, mode);
7800 return value_target;
7803 protected override void CloneTo (CloneContext clonectx, Expression t)
7805 New target = (New) t;
7807 target.RequestedType = RequestedType.Clone (clonectx);
7808 if (arguments != null){
7809 target.arguments = arguments.Clone (clonectx);
7813 public override SLE.Expression MakeExpression (BuilderContext ctx)
7816 return base.MakeExpression (ctx);
7818 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7822 public override object Accept (StructuralVisitor visitor)
7824 return visitor.Visit (this);
7829 // Array initializer expression, the expression is allowed in
7830 // variable or field initialization only which makes it tricky as
7831 // the type has to be infered based on the context either from field
7832 // type or variable type (think of multiple declarators)
7834 public class ArrayInitializer : Expression
7836 List<Expression> elements;
7837 BlockVariable variable;
7839 public ArrayInitializer (List<Expression> init, Location loc)
7845 public ArrayInitializer (int count, Location loc)
7846 : this (new List<Expression> (count), loc)
7850 public ArrayInitializer (Location loc)
7858 get { return elements.Count; }
7861 public List<Expression> Elements {
7867 public Expression this [int index] {
7869 return elements [index];
7873 public BlockVariable VariableDeclaration {
7884 public void Add (Expression expr)
7886 elements.Add (expr);
7889 public override bool ContainsEmitWithAwait ()
7891 throw new NotSupportedException ();
7894 public override Expression CreateExpressionTree (ResolveContext ec)
7896 throw new NotSupportedException ("ET");
7899 protected override void CloneTo (CloneContext clonectx, Expression t)
7901 var target = (ArrayInitializer) t;
7903 target.elements = new List<Expression> (elements.Count);
7904 foreach (var element in elements)
7905 target.elements.Add (element.Clone (clonectx));
7908 protected override Expression DoResolve (ResolveContext rc)
7910 var current_field = rc.CurrentMemberDefinition as FieldBase;
7911 TypeExpression type;
7912 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7913 type = new TypeExpression (current_field.MemberType, current_field.Location);
7914 } else if (variable != null) {
7915 if (variable.TypeExpression is VarExpr) {
7916 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7917 return EmptyExpression.Null;
7920 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7922 throw new NotImplementedException ("Unexpected array initializer context");
7925 return new ArrayCreation (type, this).Resolve (rc);
7928 public override void Emit (EmitContext ec)
7930 throw new InternalErrorException ("Missing Resolve call");
7933 public override void FlowAnalysis (FlowAnalysisContext fc)
7935 throw new InternalErrorException ("Missing Resolve call");
7938 public override object Accept (StructuralVisitor visitor)
7940 return visitor.Visit (this);
7945 /// 14.5.10.2: Represents an array creation expression.
7949 /// There are two possible scenarios here: one is an array creation
7950 /// expression that specifies the dimensions and optionally the
7951 /// initialization data and the other which does not need dimensions
7952 /// specified but where initialization data is mandatory.
7954 public class ArrayCreation : Expression
7956 FullNamedExpression requested_base_type;
7957 ArrayInitializer initializers;
7960 // The list of Argument types.
7961 // This is used to construct the `newarray' or constructor signature
7963 protected List<Expression> arguments;
7965 protected TypeSpec array_element_type;
7967 protected int dimensions;
7968 protected readonly ComposedTypeSpecifier rank;
7969 Expression first_emit;
7970 LocalTemporary first_emit_temp;
7972 protected List<Expression> array_data;
7974 Dictionary<int, int> bounds;
7977 // The number of constants in array initializers
7978 int const_initializers_count;
7979 bool only_constant_initializers;
7981 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7982 : this (requested_base_type, rank, initializers, l)
7984 arguments = new List<Expression> (exprs);
7985 num_arguments = arguments.Count;
7989 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7991 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7993 this.requested_base_type = requested_base_type;
7995 this.initializers = initializers;
7999 num_arguments = rank.Dimension;
8003 // For compiler generated single dimensional arrays only
8005 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
8006 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
8011 // For expressions like int[] foo = { 1, 2, 3 };
8013 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
8014 : this (requested_base_type, null, initializers, initializers.Location)
8018 public bool NoEmptyInterpolation { get; set; }
8020 public ComposedTypeSpecifier Rank {
8026 public FullNamedExpression TypeExpression {
8028 return this.requested_base_type;
8032 public ArrayInitializer Initializers {
8034 return this.initializers;
8038 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
8040 if (initializers != null && bounds == null) {
8042 // We use this to store all the data values in the order in which we
8043 // will need to store them in the byte blob later
8045 array_data = new List<Expression> (probe.Count);
8046 bounds = new Dictionary<int, int> ();
8049 if (specified_dims) {
8050 Expression a = arguments [idx];
8055 a = ConvertExpressionToArrayIndex (ec, a);
8061 if (initializers != null) {
8062 Constant c = a as Constant;
8063 if (c == null && a is ArrayIndexCast)
8064 c = ((ArrayIndexCast) a).Child as Constant;
8067 ec.Report.Error (150, a.Location, "A constant value is expected");
8073 value = System.Convert.ToInt32 (c.GetValue ());
8075 ec.Report.Error (150, a.Location, "A constant value is expected");
8079 // TODO: probe.Count does not fit ulong in
8080 if (value != probe.Count) {
8081 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8085 bounds[idx] = value;
8089 if (initializers == null)
8092 for (int i = 0; i < probe.Count; ++i) {
8094 if (o is ArrayInitializer) {
8095 var sub_probe = o as ArrayInitializer;
8096 if (idx + 1 >= dimensions){
8097 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8101 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8102 if (!bounds.ContainsKey(idx + 1))
8103 bounds[idx + 1] = sub_probe.Count;
8105 if (bounds[idx + 1] != sub_probe.Count) {
8106 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8110 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8113 } else if (child_bounds > 1) {
8114 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8116 Expression element = ResolveArrayElement (ec, o);
8117 if (element == null)
8120 // Initializers with the default values can be ignored
8121 Constant c = element as Constant;
8123 if (!c.IsDefaultInitializer (array_element_type)) {
8124 ++const_initializers_count;
8127 only_constant_initializers = false;
8130 array_data.Add (element);
8137 public override bool ContainsEmitWithAwait ()
8139 foreach (var arg in arguments) {
8140 if (arg.ContainsEmitWithAwait ())
8144 return InitializersContainAwait ();
8147 public override Expression CreateExpressionTree (ResolveContext ec)
8151 if (array_data == null) {
8152 args = new Arguments (arguments.Count + 1);
8153 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8154 foreach (Expression a in arguments)
8155 args.Add (new Argument (a.CreateExpressionTree (ec)));
8157 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8160 if (dimensions > 1) {
8161 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8165 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8166 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8167 if (array_data != null) {
8168 for (int i = 0; i < array_data.Count; ++i) {
8169 Expression e = array_data [i];
8170 args.Add (new Argument (e.CreateExpressionTree (ec)));
8174 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8177 void UpdateIndices (ResolveContext rc)
8180 for (var probe = initializers; probe != null;) {
8181 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8183 bounds[i++] = probe.Count;
8185 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8186 probe = (ArrayInitializer) probe[0];
8187 } else if (dimensions > i) {
8195 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8197 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8200 public override void FlowAnalysis (FlowAnalysisContext fc)
8202 foreach (var arg in arguments)
8203 arg.FlowAnalysis (fc);
8205 if (array_data != null) {
8206 foreach (var ad in array_data)
8207 ad.FlowAnalysis (fc);
8211 bool InitializersContainAwait ()
8213 if (array_data == null)
8216 foreach (var expr in array_data) {
8217 if (expr.ContainsEmitWithAwait ())
8224 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8226 element = element.Resolve (ec);
8227 if (element == null)
8230 var te = element as CompoundAssign.TargetExpression;
8232 for (int i = 1; i < initializers.Count; ++i) {
8233 if (initializers [i].ContainsEmitWithAwait ()) {
8234 te.RequiresEmitWithAwait = true;
8239 if (!te.RequiresEmitWithAwait) {
8240 if (first_emit != null)
8241 throw new InternalErrorException ("Can only handle one mutator at a time");
8242 first_emit = element;
8243 element = first_emit_temp = new LocalTemporary (element.Type);
8247 return Convert.ImplicitConversionRequired (
8248 ec, element, array_element_type, loc);
8251 protected bool ResolveInitializers (ResolveContext ec)
8254 only_constant_initializers = true;
8257 if (arguments != null) {
8259 for (int i = 0; i < arguments.Count; ++i) {
8260 res &= CheckIndices (ec, initializers, i, true, dimensions);
8261 if (initializers != null)
8268 arguments = new List<Expression> ();
8270 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8279 // Resolved the type of the array
8281 bool ResolveArrayType (ResolveContext ec)
8286 FullNamedExpression array_type_expr;
8287 if (num_arguments > 0) {
8288 array_type_expr = new ComposedCast (requested_base_type, rank);
8290 array_type_expr = requested_base_type;
8293 type = array_type_expr.ResolveAsType (ec);
8294 if (array_type_expr == null)
8297 var ac = type as ArrayContainer;
8299 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8303 array_element_type = ac.Element;
8304 dimensions = ac.Rank;
8309 protected override Expression DoResolve (ResolveContext ec)
8314 if (!ResolveArrayType (ec))
8318 // validate the initializers and fill in any missing bits
8320 if (!ResolveInitializers (ec))
8323 eclass = ExprClass.Value;
8327 byte [] MakeByteBlob ()
8332 int count = array_data.Count;
8334 TypeSpec element_type = array_element_type;
8335 if (element_type.IsEnum)
8336 element_type = EnumSpec.GetUnderlyingType (element_type);
8338 factor = BuiltinTypeSpec.GetSize (element_type);
8340 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8342 data = new byte [(count * factor + 3) & ~3];
8345 for (int i = 0; i < count; ++i) {
8346 var c = array_data[i] as Constant;
8352 object v = c.GetValue ();
8354 switch (element_type.BuiltinType) {
8355 case BuiltinTypeSpec.Type.Long:
8356 long lval = (long) v;
8358 for (int j = 0; j < factor; ++j) {
8359 data[idx + j] = (byte) (lval & 0xFF);
8363 case BuiltinTypeSpec.Type.ULong:
8364 ulong ulval = (ulong) v;
8366 for (int j = 0; j < factor; ++j) {
8367 data[idx + j] = (byte) (ulval & 0xFF);
8368 ulval = (ulval >> 8);
8371 case BuiltinTypeSpec.Type.Float:
8372 var fval = SingleConverter.SingleToInt32Bits((float) v);
8374 data[idx] = (byte) (fval & 0xff);
8375 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8376 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8377 data[idx + 3] = (byte) (fval >> 24);
8379 case BuiltinTypeSpec.Type.Double:
8380 element = BitConverter.GetBytes ((double) v);
8382 for (int j = 0; j < factor; ++j)
8383 data[idx + j] = element[j];
8385 // FIXME: Handle the ARM float format.
8386 if (!BitConverter.IsLittleEndian)
8387 System.Array.Reverse (data, idx, 8);
8389 case BuiltinTypeSpec.Type.Char:
8390 int chval = (int) ((char) v);
8392 data[idx] = (byte) (chval & 0xff);
8393 data[idx + 1] = (byte) (chval >> 8);
8395 case BuiltinTypeSpec.Type.Short:
8396 int sval = (int) ((short) v);
8398 data[idx] = (byte) (sval & 0xff);
8399 data[idx + 1] = (byte) (sval >> 8);
8401 case BuiltinTypeSpec.Type.UShort:
8402 int usval = (int) ((ushort) v);
8404 data[idx] = (byte) (usval & 0xff);
8405 data[idx + 1] = (byte) (usval >> 8);
8407 case BuiltinTypeSpec.Type.Int:
8410 data[idx] = (byte) (val & 0xff);
8411 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8412 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8413 data[idx + 3] = (byte) (val >> 24);
8415 case BuiltinTypeSpec.Type.UInt:
8416 uint uval = (uint) v;
8418 data[idx] = (byte) (uval & 0xff);
8419 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8420 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8421 data[idx + 3] = (byte) (uval >> 24);
8423 case BuiltinTypeSpec.Type.SByte:
8424 data[idx] = (byte) (sbyte) v;
8426 case BuiltinTypeSpec.Type.Byte:
8427 data[idx] = (byte) v;
8429 case BuiltinTypeSpec.Type.Bool:
8430 data[idx] = (byte) ((bool) v ? 1 : 0);
8432 case BuiltinTypeSpec.Type.Decimal:
8433 int[] bits = Decimal.GetBits ((decimal) v);
8436 // FIXME: For some reason, this doesn't work on the MS runtime.
8437 int[] nbits = new int[4];
8443 for (int j = 0; j < 4; j++) {
8444 data[p++] = (byte) (nbits[j] & 0xff);
8445 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8446 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8447 data[p++] = (byte) (nbits[j] >> 24);
8451 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8460 public override SLE.Expression MakeExpression (BuilderContext ctx)
8463 return base.MakeExpression (ctx);
8465 var initializers = new SLE.Expression [array_data.Count];
8466 for (var i = 0; i < initializers.Length; i++) {
8467 if (array_data [i] == null)
8468 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8470 initializers [i] = array_data [i].MakeExpression (ctx);
8473 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8478 // Emits the initializers for the array
8480 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8482 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8487 // First, the static data
8489 byte [] data = MakeByteBlob ();
8490 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8492 if (stackArray == null) {
8493 ec.Emit (OpCodes.Dup);
8495 stackArray.Emit (ec);
8498 ec.Emit (OpCodes.Ldtoken, fb);
8499 ec.Emit (OpCodes.Call, m);
8504 // Emits pieces of the array that can not be computed at compile
8505 // time (variables and string locations).
8507 // This always expect the top value on the stack to be the array
8509 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8511 int dims = bounds.Count;
8512 var current_pos = new int [dims];
8514 for (int i = 0; i < array_data.Count; i++){
8516 Expression e = array_data [i];
8517 var c = e as Constant;
8519 // Constant can be initialized via StaticInitializer
8520 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8524 if (stackArray != null) {
8525 if (e.ContainsEmitWithAwait ()) {
8526 e = e.EmitToField (ec);
8529 stackArray.EmitLoad (ec);
8531 ec.Emit (OpCodes.Dup);
8534 for (int idx = 0; idx < dims; idx++)
8535 ec.EmitInt (current_pos [idx]);
8538 // If we are dealing with a struct, get the
8539 // address of it, so we can store it.
8541 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8542 ec.Emit (OpCodes.Ldelema, etype);
8546 ec.EmitArrayStore ((ArrayContainer) type);
8552 for (int j = dims - 1; j >= 0; j--){
8554 if (current_pos [j] < bounds [j])
8556 current_pos [j] = 0;
8560 if (stackArray != null)
8561 stackArray.PrepareCleanup (ec);
8564 public override void Emit (EmitContext ec)
8566 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8569 var await_field = EmitToFieldSource (ec);
8570 if (await_field != null)
8571 await_field.Emit (ec);
8574 bool EmitOptimizedEmpty (EmitContext ec)
8576 if (arguments.Count != 1 || dimensions != 1)
8579 var c = arguments [0] as Constant;
8580 if (c == null || !c.IsZeroInteger)
8583 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8584 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8587 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8588 ec.Emit (OpCodes.Call, m);
8592 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8594 if (first_emit != null) {
8595 first_emit.Emit (ec);
8596 first_emit_temp.Store (ec);
8599 StackFieldExpr await_stack_field;
8600 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8601 await_stack_field = ec.GetTemporaryField (type);
8604 await_stack_field = null;
8607 EmitExpressionsList (ec, arguments);
8609 ec.EmitArrayNew ((ArrayContainer) type);
8611 if (initializers == null)
8612 return await_stack_field;
8614 if (await_stack_field != null)
8615 await_stack_field.EmitAssignFromStack (ec);
8619 // Emit static initializer for arrays which contain more than 2 items and
8620 // the static initializer will initialize at least 25% of array values or there
8621 // is more than 10 items to be initialized
8623 // NOTE: const_initializers_count does not contain default constant values.
8625 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8626 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8627 EmitStaticInitializers (ec, await_stack_field);
8629 if (!only_constant_initializers)
8630 EmitDynamicInitializers (ec, false, await_stack_field);
8634 EmitDynamicInitializers (ec, true, await_stack_field);
8637 if (first_emit_temp != null)
8638 first_emit_temp.Release (ec);
8640 return await_stack_field;
8643 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8645 // no multi dimensional or jagged arrays
8646 if (arguments.Count != 1 || array_element_type.IsArray) {
8647 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8651 // No array covariance, except for array -> object
8652 if (type != targetType) {
8653 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8654 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8658 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8659 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8664 // Single dimensional array of 0 size
8665 if (array_data == null) {
8666 IntConstant ic = arguments[0] as IntConstant;
8667 if (ic == null || !ic.IsDefaultValue) {
8668 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8676 enc.Encode (array_data.Count);
8677 foreach (var element in array_data) {
8678 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8682 protected override void CloneTo (CloneContext clonectx, Expression t)
8684 ArrayCreation target = (ArrayCreation) t;
8686 if (requested_base_type != null)
8687 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8689 if (arguments != null){
8690 target.arguments = new List<Expression> (arguments.Count);
8691 foreach (Expression e in arguments)
8692 target.arguments.Add (e.Clone (clonectx));
8695 if (initializers != null)
8696 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8699 public override object Accept (StructuralVisitor visitor)
8701 return visitor.Visit (this);
8706 // Represents an implicitly typed array epxression
8708 class ImplicitlyTypedArrayCreation : ArrayCreation
8710 TypeInferenceContext best_type_inference;
8712 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8713 : base (null, rank, initializers, loc)
8717 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8718 : base (null, initializers, loc)
8722 protected override Expression DoResolve (ResolveContext ec)
8727 dimensions = rank.Dimension;
8729 best_type_inference = new TypeInferenceContext ();
8731 if (!ResolveInitializers (ec))
8734 best_type_inference.FixAllTypes (ec);
8735 array_element_type = best_type_inference.InferredTypeArguments[0];
8736 best_type_inference = null;
8738 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
8739 ec.Report.Error (826, loc,
8740 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8745 // At this point we found common base type for all initializer elements
8746 // but we have to be sure that all static initializer elements are of
8749 UnifyInitializerElement (ec);
8751 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8752 eclass = ExprClass.Value;
8757 // Converts static initializer only
8759 void UnifyInitializerElement (ResolveContext ec)
8761 for (int i = 0; i < array_data.Count; ++i) {
8762 Expression e = array_data[i];
8764 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8768 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8770 element = element.Resolve (ec);
8771 if (element != null)
8772 best_type_inference.AddCommonTypeBound (element.Type);
8778 sealed class CompilerGeneratedThis : This
8780 public CompilerGeneratedThis (TypeSpec type, Location loc)
8786 protected override Expression DoResolve (ResolveContext rc)
8788 eclass = ExprClass.Variable;
8790 var block = rc.CurrentBlock;
8791 if (block != null) {
8792 var top = block.ParametersBlock.TopBlock;
8793 if (top.ThisVariable != null)
8794 variable_info = top.ThisVariable.VariableInfo;
8801 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8803 return DoResolve (rc);
8806 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8813 /// Represents the `this' construct
8816 public class This : VariableReference
8818 sealed class ThisVariable : ILocalVariable
8820 public static readonly ILocalVariable Instance = new ThisVariable ();
8822 public void Emit (EmitContext ec)
8827 public void EmitAssign (EmitContext ec)
8829 throw new InvalidOperationException ();
8832 public void EmitAddressOf (EmitContext ec)
8838 protected VariableInfo variable_info;
8840 public This (Location loc)
8847 public override string Name {
8848 get { return "this"; }
8851 public override bool IsLockedByStatement {
8859 public override bool IsRef {
8860 get { return type.IsStruct; }
8863 public override bool IsSideEffectFree {
8869 protected override ILocalVariable Variable {
8870 get { return ThisVariable.Instance; }
8873 public override VariableInfo VariableInfo {
8874 get { return variable_info; }
8877 public override bool IsFixed {
8878 get { return false; }
8883 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8886 // It's null for all cases when we don't need to check `this'
8887 // definitive assignment
8889 if (variable_info == null)
8892 if (fc.IsDefinitelyAssigned (variable_info))
8895 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8898 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8900 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8901 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8902 } else if (ec.CurrentAnonymousMethod != null) {
8903 ec.Report.Error (1673, loc,
8904 "Anonymous methods inside structs cannot access instance members of `this'. " +
8905 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8907 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8911 public override void FlowAnalysis (FlowAnalysisContext fc)
8913 CheckStructThisDefiniteAssignment (fc);
8916 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8921 AnonymousMethodStorey storey = ae.Storey;
8922 return storey != null ? storey.HoistedThis : null;
8925 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8927 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8930 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8933 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8939 public virtual void ResolveBase (ResolveContext ec)
8941 eclass = ExprClass.Variable;
8942 type = ec.CurrentType;
8944 if (!IsThisAvailable (ec, false)) {
8945 Error_ThisNotAvailable (ec);
8949 var block = ec.CurrentBlock;
8950 if (block != null) {
8951 var top = block.ParametersBlock.TopBlock;
8952 if (top.ThisVariable != null)
8953 variable_info = top.ThisVariable.VariableInfo;
8955 AnonymousExpression am = ec.CurrentAnonymousMethod;
8956 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8958 // Hoisted this is almost like hoisted variable but not exactly. When
8959 // there is no variable hoisted we can simply emit an instance method
8960 // without lifting this into a storey. Unfotunatelly this complicates
8961 // things in other cases because we don't know where this will be hoisted
8962 // until top-level block is fully resolved
8964 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8965 am.SetHasThisAccess ();
8970 protected override Expression DoResolve (ResolveContext ec)
8976 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8978 if (eclass == ExprClass.Unresolved)
8982 if (right_side == EmptyExpression.UnaryAddress)
8983 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8984 else if (right_side == EmptyExpression.OutAccess)
8985 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8987 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8993 public override int GetHashCode()
8995 throw new NotImplementedException ();
8998 public override bool Equals (object obj)
9000 This t = obj as This;
9007 protected override void CloneTo (CloneContext clonectx, Expression t)
9012 public override void SetHasAddressTaken ()
9017 public override object Accept (StructuralVisitor visitor)
9019 return visitor.Visit (this);
9024 /// Represents the `__arglist' construct
9026 public class ArglistAccess : Expression
9028 public ArglistAccess (Location loc)
9033 protected override void CloneTo (CloneContext clonectx, Expression target)
9038 public override bool ContainsEmitWithAwait ()
9043 public override Expression CreateExpressionTree (ResolveContext ec)
9045 throw new NotSupportedException ("ET");
9048 protected override Expression DoResolve (ResolveContext ec)
9050 eclass = ExprClass.Variable;
9051 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
9053 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
9054 ec.Report.Error (190, loc,
9055 "The __arglist construct is valid only within a variable argument method");
9061 public override void Emit (EmitContext ec)
9063 ec.Emit (OpCodes.Arglist);
9066 public override object Accept (StructuralVisitor visitor)
9068 return visitor.Visit (this);
9073 /// Represents the `__arglist (....)' construct
9075 public class Arglist : Expression
9077 Arguments arguments;
9079 public Arglist (Location loc)
9084 public Arglist (Arguments args, Location l)
9090 public Arguments Arguments {
9096 public MetaType[] ArgumentTypes {
9098 if (arguments == null)
9099 return MetaType.EmptyTypes;
9101 var retval = new MetaType[arguments.Count];
9102 for (int i = 0; i < retval.Length; i++)
9103 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9109 public override bool ContainsEmitWithAwait ()
9111 throw new NotImplementedException ();
9114 public override Expression CreateExpressionTree (ResolveContext ec)
9116 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9120 protected override Expression DoResolve (ResolveContext ec)
9122 eclass = ExprClass.Variable;
9123 type = InternalType.Arglist;
9124 if (arguments != null) {
9125 bool dynamic; // Can be ignored as there is always only 1 overload
9126 arguments.Resolve (ec, out dynamic);
9132 public override void Emit (EmitContext ec)
9134 if (arguments != null)
9135 arguments.Emit (ec);
9138 protected override void CloneTo (CloneContext clonectx, Expression t)
9140 Arglist target = (Arglist) t;
9142 if (arguments != null)
9143 target.arguments = arguments.Clone (clonectx);
9146 public override object Accept (StructuralVisitor visitor)
9148 return visitor.Visit (this);
9152 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9154 FullNamedExpression texpr;
9156 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9163 public FullNamedExpression TypeExpression {
9169 public override bool ContainsEmitWithAwait ()
9174 public void AddressOf (EmitContext ec, AddressOp mode)
9177 ec.Emit (OpCodes.Refanyval, type);
9180 protected override Expression DoResolve (ResolveContext rc)
9182 expr = expr.Resolve (rc);
9183 type = texpr.ResolveAsType (rc);
9184 if (expr == null || type == null)
9187 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9188 eclass = ExprClass.Variable;
9192 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9194 return DoResolve (rc);
9197 public override void Emit (EmitContext ec)
9200 ec.Emit (OpCodes.Refanyval, type);
9201 ec.EmitLoadFromPtr (type);
9204 public void Emit (EmitContext ec, bool leave_copy)
9206 throw new NotImplementedException ();
9209 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9212 ec.Emit (OpCodes.Refanyval, type);
9215 LocalTemporary temporary = null;
9217 ec.Emit (OpCodes.Dup);
9218 temporary = new LocalTemporary (source.Type);
9219 temporary.Store (ec);
9222 ec.EmitStoreFromPtr (type);
9224 if (temporary != null) {
9225 temporary.Emit (ec);
9226 temporary.Release (ec);
9230 public override object Accept (StructuralVisitor visitor)
9232 return visitor.Visit (this);
9236 public class RefTypeExpr : ShimExpression
9238 public RefTypeExpr (Expression expr, Location loc)
9244 protected override Expression DoResolve (ResolveContext rc)
9246 expr = expr.Resolve (rc);
9250 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9254 type = rc.BuiltinTypes.Type;
9255 eclass = ExprClass.Value;
9259 public override void Emit (EmitContext ec)
9262 ec.Emit (OpCodes.Refanytype);
9263 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9265 ec.Emit (OpCodes.Call, m);
9268 public override object Accept (StructuralVisitor visitor)
9270 return visitor.Visit (this);
9274 public class MakeRefExpr : ShimExpression
9276 public MakeRefExpr (Expression expr, Location loc)
9282 public override bool ContainsEmitWithAwait ()
9284 throw new NotImplementedException ();
9287 protected override Expression DoResolve (ResolveContext rc)
9289 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9290 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9291 eclass = ExprClass.Value;
9295 public override void Emit (EmitContext ec)
9297 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9298 ec.Emit (OpCodes.Mkrefany, expr.Type);
9301 public override object Accept (StructuralVisitor visitor)
9303 return visitor.Visit (this);
9308 /// Implements the typeof operator
9310 public class TypeOf : Expression {
9311 FullNamedExpression QueriedType;
9314 public TypeOf (FullNamedExpression queried_type, Location l)
9316 QueriedType = queried_type;
9321 // Use this constructor for any compiler generated typeof expression
9323 public TypeOf (TypeSpec type, Location loc)
9325 this.typearg = type;
9331 public override bool IsSideEffectFree {
9337 public TypeSpec TypeArgument {
9343 public FullNamedExpression TypeExpression {
9352 protected override void CloneTo (CloneContext clonectx, Expression t)
9354 TypeOf target = (TypeOf) t;
9355 if (QueriedType != null)
9356 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9359 public override bool ContainsEmitWithAwait ()
9364 public override Expression CreateExpressionTree (ResolveContext ec)
9366 Arguments args = new Arguments (2);
9367 args.Add (new Argument (this));
9368 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9369 return CreateExpressionFactoryCall (ec, "Constant", args);
9372 protected override Expression DoResolve (ResolveContext ec)
9374 if (eclass != ExprClass.Unresolved)
9377 if (typearg == null) {
9379 // Pointer types are allowed without explicit unsafe, they are just tokens
9381 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9382 typearg = QueriedType.ResolveAsType (ec, true);
9385 if (typearg == null)
9388 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9389 ec.Report.Error (1962, QueriedType.Location,
9390 "The typeof operator cannot be used on the dynamic type");
9394 type = ec.BuiltinTypes.Type;
9396 // Even though what is returned is a type object, it's treated as a value by the compiler.
9397 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9398 eclass = ExprClass.Value;
9402 static bool ContainsDynamicType (TypeSpec type)
9404 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9407 var element_container = type as ElementTypeSpec;
9408 if (element_container != null)
9409 return ContainsDynamicType (element_container.Element);
9411 foreach (var t in type.TypeArguments) {
9412 if (ContainsDynamicType (t)) {
9420 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9422 // Target type is not System.Type therefore must be object
9423 // and we need to use different encoding sequence
9424 if (targetType != type)
9427 if (typearg is InflatedTypeSpec) {
9430 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9431 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9432 typearg.GetSignatureForError ());
9436 gt = gt.DeclaringType;
9437 } while (gt != null);
9440 if (ContainsDynamicType (typearg)) {
9441 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9445 enc.EncodeTypeName (typearg);
9448 public override void Emit (EmitContext ec)
9450 ec.Emit (OpCodes.Ldtoken, typearg);
9451 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9453 ec.Emit (OpCodes.Call, m);
9456 public override object Accept (StructuralVisitor visitor)
9458 return visitor.Visit (this);
9462 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9464 public TypeOfMethod (MethodSpec method, Location loc)
9465 : base (method, loc)
9469 protected override Expression DoResolve (ResolveContext ec)
9471 if (member.IsConstructor) {
9472 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9474 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9480 return base.DoResolve (ec);
9483 public override void Emit (EmitContext ec)
9485 ec.Emit (OpCodes.Ldtoken, member);
9488 ec.Emit (OpCodes.Castclass, type);
9491 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9493 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9496 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9498 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9502 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9504 protected readonly T member;
9506 protected TypeOfMember (T member, Location loc)
9508 this.member = member;
9512 public override bool IsSideEffectFree {
9518 public override bool ContainsEmitWithAwait ()
9523 public override Expression CreateExpressionTree (ResolveContext ec)
9525 Arguments args = new Arguments (2);
9526 args.Add (new Argument (this));
9527 args.Add (new Argument (new TypeOf (type, loc)));
9528 return CreateExpressionFactoryCall (ec, "Constant", args);
9531 protected override Expression DoResolve (ResolveContext ec)
9533 eclass = ExprClass.Value;
9537 public override void Emit (EmitContext ec)
9539 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9540 PredefinedMember<MethodSpec> p;
9542 p = GetTypeFromHandleGeneric (ec);
9543 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9545 p = GetTypeFromHandle (ec);
9548 var mi = p.Resolve (loc);
9550 ec.Emit (OpCodes.Call, mi);
9553 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9554 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9557 sealed class TypeOfField : TypeOfMember<FieldSpec>
9559 public TypeOfField (FieldSpec field, Location loc)
9564 protected override Expression DoResolve (ResolveContext ec)
9566 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9570 return base.DoResolve (ec);
9573 public override void Emit (EmitContext ec)
9575 ec.Emit (OpCodes.Ldtoken, member);
9579 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9581 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9584 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9586 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9591 /// Implements the sizeof expression
9593 public class SizeOf : Expression {
9594 readonly Expression texpr;
9595 TypeSpec type_queried;
9597 public SizeOf (Expression queried_type, Location l)
9599 this.texpr = queried_type;
9603 public override bool IsSideEffectFree {
9609 public Expression TypeExpression {
9615 public override bool ContainsEmitWithAwait ()
9620 public override Expression CreateExpressionTree (ResolveContext ec)
9622 Error_PointerInsideExpressionTree (ec);
9626 protected override Expression DoResolve (ResolveContext ec)
9628 type_queried = texpr.ResolveAsType (ec);
9629 if (type_queried == null)
9632 if (type_queried.IsEnum)
9633 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9635 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9637 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9640 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9645 ec.Report.Error (233, loc,
9646 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9647 type_queried.GetSignatureForError ());
9650 type = ec.BuiltinTypes.Int;
9651 eclass = ExprClass.Value;
9655 public override void Emit (EmitContext ec)
9657 ec.Emit (OpCodes.Sizeof, type_queried);
9660 protected override void CloneTo (CloneContext clonectx, Expression t)
9664 public override object Accept (StructuralVisitor visitor)
9666 return visitor.Visit (this);
9671 /// Implements the qualified-alias-member (::) expression.
9673 public class QualifiedAliasMember : MemberAccess
9675 readonly string alias;
9676 public static readonly string GlobalAlias = "global";
9678 public QualifiedAliasMember (string alias, string identifier, Location l)
9679 : base (null, identifier, l)
9684 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9685 : base (null, identifier, targs, l)
9690 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9691 : base (null, identifier, arity, l)
9696 public string Alias {
9702 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9704 if (alias == GlobalAlias)
9705 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9707 int errors = mc.Module.Compiler.Report.Errors;
9708 var expr = mc.LookupNamespaceAlias (alias);
9710 if (errors == mc.Module.Compiler.Report.Errors)
9711 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9719 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9721 expr = CreateExpressionFromAlias (mc);
9725 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9728 protected override Expression DoResolve (ResolveContext rc)
9730 return ResolveAsTypeOrNamespace (rc, false);
9733 public override string GetSignatureForError ()
9736 if (targs != null) {
9737 name = Name + "<" + targs.GetSignatureForError () + ">";
9740 return alias + "::" + name;
9743 public override bool HasConditionalAccess ()
9748 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9750 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9751 rc.Module.Compiler.Report.Error (687, loc,
9752 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9753 GetSignatureForError ());
9758 return DoResolve (rc);
9761 protected override void CloneTo (CloneContext clonectx, Expression t)
9766 public override object Accept (StructuralVisitor visitor)
9768 return visitor.Visit (this);
9773 /// Implements the member access expression
9775 public class MemberAccess : ATypeNameExpression
9777 protected Expression expr;
9779 public MemberAccess (Expression expr, string id)
9780 : base (id, expr.Location)
9785 public MemberAccess (Expression expr, string identifier, Location loc)
9786 : base (identifier, loc)
9791 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9792 : base (identifier, args, loc)
9797 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9798 : base (identifier, arity, loc)
9803 public Expression LeftExpression {
9809 public override Location StartLocation {
9811 return expr == null ? loc : expr.StartLocation;
9815 protected override Expression DoResolve (ResolveContext rc)
9817 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9819 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9824 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9826 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9828 if (e is TypeExpr) {
9829 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9834 e = e.ResolveLValue (rc, rhs);
9839 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9841 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9842 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9844 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9847 public override bool HasConditionalAccess ()
9849 return LeftExpression.HasConditionalAccess ();
9852 public static bool IsValidDotExpression (TypeSpec type)
9854 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9855 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9857 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9860 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9862 var sn = expr as SimpleName;
9863 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9866 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9869 // Resolve expression which does have type set as we need expression type
9870 // with disable flow analysis as we don't know whether left side expression
9871 // is used as variable or type
9873 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9874 expr = expr.Resolve (rc);
9875 } else if (expr is TypeParameterExpr) {
9876 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9880 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9881 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9882 expr = expr.Resolve (rc, flags);
9885 expr = expr.Resolve (rc, flags);
9892 var ns = expr as NamespaceExpression;
9894 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9896 if (retval == null) {
9897 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9902 if (HasTypeArguments)
9903 return new GenericTypeExpr (retval.Type, targs, loc);
9905 targs.Resolve (rc, false);
9911 var cma = this as ConditionalMemberAccess;
9914 TypeSpec expr_type = expr.Type;
9915 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9916 me = expr as MemberExpr;
9918 me.ResolveInstanceExpression (rc, null);
9920 Arguments args = new Arguments (1);
9921 args.Add (new Argument (expr));
9924 return new DynamicConditionalMemberBinder (Name, args, loc);
9926 return new DynamicMemberBinder (Name, args, loc);
9930 if (!IsNullPropagatingValid (expr.Type)) {
9931 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9935 if (expr_type.IsNullableType) {
9936 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9937 expr_type = expr.Type;
9941 if (!IsValidDotExpression (expr_type)) {
9942 Error_OperatorCannotBeApplied (rc, expr_type);
9946 var lookup_arity = Arity;
9947 bool errorMode = false;
9948 Expression member_lookup;
9950 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9951 if (member_lookup == null) {
9953 // Try to look for extension method when member lookup failed
9955 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9956 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9957 if (methods != null) {
9958 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9959 if (HasTypeArguments) {
9960 if (!targs.Resolve (rc, false))
9963 emg.SetTypeArguments (rc, targs);
9967 emg.ConditionalAccess = true;
9969 // TODO: it should really skip the checks bellow
9970 return emg.Resolve (rc);
9976 if (member_lookup == null) {
9977 var dep = expr_type.GetMissingDependencies ();
9979 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9980 } else if (expr is TypeExpr) {
9981 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9983 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9989 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9990 // Leave it to overload resolution to report correct error
9991 } else if (!(member_lookup is TypeExpr)) {
9992 // TODO: rc.SymbolRelatedToPreviousError
9993 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9998 if (member_lookup != null)
10002 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
10006 TypeExpr texpr = member_lookup as TypeExpr;
10007 if (texpr != null) {
10008 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
10009 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
10010 Name, texpr.GetSignatureForError ());
10013 if (!texpr.Type.IsAccessible (rc)) {
10014 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
10015 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
10019 if (HasTypeArguments) {
10020 return new GenericTypeExpr (member_lookup.Type, targs, loc);
10023 return member_lookup;
10026 me = member_lookup as MemberExpr;
10028 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
10033 me.ConditionalAccess = true;
10036 me = me.ResolveMemberAccess (rc, expr, sn);
10039 if (!targs.Resolve (rc, false))
10042 me.SetTypeArguments (rc, targs);
10048 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
10050 FullNamedExpression fexpr = expr as FullNamedExpression;
10051 if (fexpr == null) {
10052 expr.ResolveAsType (rc);
10056 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
10058 if (expr_resolved == null)
10061 var ns = expr_resolved as NamespaceExpression;
10063 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10065 if (retval == null) {
10066 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10067 } else if (Arity > 0) {
10068 if (HasTypeArguments) {
10069 retval = new GenericTypeExpr (retval.Type, targs, loc);
10070 if (retval.ResolveAsType (rc) == null)
10073 targs.Resolve (rc, allowUnboundTypeArguments);
10075 retval = new GenericOpenTypeExpr (retval.Type, loc);
10082 var tnew_expr = expr_resolved.ResolveAsType (rc);
10083 if (tnew_expr == null)
10086 TypeSpec expr_type = tnew_expr;
10087 if (TypeManager.IsGenericParameter (expr_type)) {
10088 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10089 tnew_expr.GetSignatureForError ());
10093 var qam = this as QualifiedAliasMember;
10095 rc.Module.Compiler.Report.Error (431, loc,
10096 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10101 TypeSpec nested = null;
10102 while (expr_type != null) {
10103 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10104 if (nested == null) {
10105 if (expr_type == tnew_expr) {
10106 Error_IdentifierNotFound (rc, expr_type);
10110 expr_type = tnew_expr;
10111 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10112 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10116 if (nested.IsAccessible (rc))
10120 // Keep looking after inaccessible candidate but only if
10121 // we are not in same context as the definition itself
10123 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10126 expr_type = expr_type.BaseType;
10131 if (HasTypeArguments) {
10132 texpr = new GenericTypeExpr (nested, targs, loc);
10134 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10136 texpr = new GenericOpenTypeExpr (nested, loc);
10138 } else if (expr_resolved is GenericOpenTypeExpr) {
10139 texpr = new GenericOpenTypeExpr (nested, loc);
10141 texpr = new TypeExpression (nested, loc);
10144 if (texpr.ResolveAsType (rc) == null)
10150 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10152 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10154 if (nested != null) {
10155 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10159 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10160 if (any_other_member != null) {
10161 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10165 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10166 Name, expr_type.GetSignatureForError ());
10169 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10171 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10174 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10176 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10177 ec.Report.SymbolRelatedToPreviousError (type);
10179 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10181 // a using directive or an assembly reference
10182 if (cand != null) {
10183 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10185 missing = "an assembly reference";
10188 ec.Report.Error (1061, loc,
10189 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10190 type.GetSignatureForError (), name, missing);
10194 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10197 public override string GetSignatureForError ()
10199 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10202 protected override void CloneTo (CloneContext clonectx, Expression t)
10204 MemberAccess target = (MemberAccess) t;
10206 target.expr = expr.Clone (clonectx);
10209 public override object Accept (StructuralVisitor visitor)
10211 return visitor.Visit (this);
10215 public class ConditionalMemberAccess : MemberAccess
10217 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10218 : base (expr, identifier, args, loc)
10222 public override bool HasConditionalAccess ()
10229 /// Implements checked expressions
10231 public class CheckedExpr : Expression {
10233 public Expression Expr;
10235 public CheckedExpr (Expression e, Location l)
10241 public override bool ContainsEmitWithAwait ()
10243 return Expr.ContainsEmitWithAwait ();
10246 public override Expression CreateExpressionTree (ResolveContext ec)
10248 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10249 return Expr.CreateExpressionTree (ec);
10252 protected override Expression DoResolve (ResolveContext ec)
10254 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10255 Expr = Expr.Resolve (ec);
10260 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10263 eclass = Expr.eclass;
10268 public override void Emit (EmitContext ec)
10270 using (ec.With (EmitContext.Options.CheckedScope, true))
10274 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10276 using (ec.With (EmitContext.Options.CheckedScope, true))
10277 Expr.EmitBranchable (ec, target, on_true);
10280 public override void FlowAnalysis (FlowAnalysisContext fc)
10282 Expr.FlowAnalysis (fc);
10285 public override SLE.Expression MakeExpression (BuilderContext ctx)
10287 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10288 return Expr.MakeExpression (ctx);
10292 protected override void CloneTo (CloneContext clonectx, Expression t)
10294 CheckedExpr target = (CheckedExpr) t;
10296 target.Expr = Expr.Clone (clonectx);
10299 public override object Accept (StructuralVisitor visitor)
10301 return visitor.Visit (this);
10306 /// Implements the unchecked expression
10308 public class UnCheckedExpr : Expression {
10310 public Expression Expr;
10312 public UnCheckedExpr (Expression e, Location l)
10318 public override bool ContainsEmitWithAwait ()
10320 return Expr.ContainsEmitWithAwait ();
10323 public override Expression CreateExpressionTree (ResolveContext ec)
10325 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10326 return Expr.CreateExpressionTree (ec);
10329 protected override Expression DoResolve (ResolveContext ec)
10331 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10332 Expr = Expr.Resolve (ec);
10337 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10340 eclass = Expr.eclass;
10345 public override void Emit (EmitContext ec)
10347 using (ec.With (EmitContext.Options.CheckedScope, false))
10351 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10353 using (ec.With (EmitContext.Options.CheckedScope, false))
10354 Expr.EmitBranchable (ec, target, on_true);
10357 public override void FlowAnalysis (FlowAnalysisContext fc)
10359 Expr.FlowAnalysis (fc);
10362 protected override void CloneTo (CloneContext clonectx, Expression t)
10364 UnCheckedExpr target = (UnCheckedExpr) t;
10366 target.Expr = Expr.Clone (clonectx);
10369 public override object Accept (StructuralVisitor visitor)
10371 return visitor.Visit (this);
10376 /// An Element Access expression.
10378 /// During semantic analysis these are transformed into
10379 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10381 public class ElementAccess : Expression
10383 public Arguments Arguments;
10384 public Expression Expr;
10385 bool conditional_access_receiver;
10387 public ElementAccess (Expression e, Arguments args, Location loc)
10391 this.Arguments = args;
10394 public bool ConditionalAccess { get; set; }
10396 public override Location StartLocation {
10398 return Expr.StartLocation;
10402 public override bool ContainsEmitWithAwait ()
10404 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10408 // We perform some simple tests, and then to "split" the emit and store
10409 // code we create an instance of a different class, and return that.
10411 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10413 if (conditionalAccessReceiver)
10414 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10416 Expr = Expr.Resolve (ec);
10418 if (conditionalAccessReceiver)
10419 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10426 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10427 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10431 if (type.IsArray) {
10432 var aa = new ArrayAccess (this, loc) {
10433 ConditionalAccess = ConditionalAccess,
10436 if (conditionalAccessReceiver)
10437 aa.SetConditionalAccessReceiver ();
10442 if (type.IsPointer)
10443 return Expr.MakePointerAccess (ec, type, Arguments);
10445 FieldExpr fe = Expr as FieldExpr;
10447 var ff = fe.Spec as FixedFieldSpec;
10449 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10453 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10454 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10455 var indexer = new IndexerExpr (indexers, type, this) {
10456 ConditionalAccess = ConditionalAccess
10459 if (conditionalAccessReceiver)
10460 indexer.SetConditionalAccessReceiver ();
10465 Error_CannotApplyIndexing (ec, type, loc);
10470 public override Expression CreateExpressionTree (ResolveContext ec)
10472 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10473 Expr.CreateExpressionTree (ec));
10475 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10478 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10480 if (type != InternalType.ErrorType) {
10481 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10482 type.GetSignatureForError ());
10486 public override bool HasConditionalAccess ()
10488 return ConditionalAccess || Expr.HasConditionalAccess ();
10491 void ResolveConditionalAccessReceiver (ResolveContext rc)
10493 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10494 conditional_access_receiver = true;
10498 protected override Expression DoResolve (ResolveContext rc)
10500 ResolveConditionalAccessReceiver (rc);
10502 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10506 return expr.Resolve (rc);
10509 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10511 var res = CreateAccessExpression (ec, false);
10515 return res.ResolveLValue (ec, rhs);
10518 public override void Emit (EmitContext ec)
10520 throw new Exception ("Should never be reached");
10523 public override void FlowAnalysis (FlowAnalysisContext fc)
10525 Expr.FlowAnalysis (fc);
10527 Arguments.FlowAnalysis (fc);
10530 public override string GetSignatureForError ()
10532 return Expr.GetSignatureForError ();
10535 protected override void CloneTo (CloneContext clonectx, Expression t)
10537 ElementAccess target = (ElementAccess) t;
10539 target.Expr = Expr.Clone (clonectx);
10540 if (Arguments != null)
10541 target.Arguments = Arguments.Clone (clonectx);
10544 public override object Accept (StructuralVisitor visitor)
10546 return visitor.Visit (this);
10551 /// Implements array access
10553 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10555 // Points to our "data" repository
10559 LocalTemporary temp;
10561 bool? has_await_args;
10562 bool conditional_access_receiver;
10564 public ArrayAccess (ElementAccess ea_data, Location l)
10570 public bool ConditionalAccess { get; set; }
10572 public void AddressOf (EmitContext ec, AddressOp mode)
10574 var ac = (ArrayContainer) ea.Expr.Type;
10576 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10577 LoadInstanceAndArguments (ec, false, true);
10580 LoadInstanceAndArguments (ec, false, false);
10582 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10583 ec.Emit (OpCodes.Readonly);
10585 ec.EmitArrayAddress (ac);
10588 public override Expression CreateExpressionTree (ResolveContext ec)
10590 if (ConditionalAccess)
10591 Error_NullShortCircuitInsideExpressionTree (ec);
10593 return ea.CreateExpressionTree (ec);
10596 public override bool ContainsEmitWithAwait ()
10598 return ea.ContainsEmitWithAwait ();
10601 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10603 if (HasConditionalAccess ())
10604 Error_NullPropagatingLValue (ec);
10606 return DoResolve (ec);
10609 protected override Expression DoResolve (ResolveContext ec)
10611 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10613 ea.Arguments.Resolve (ec, out dynamic);
10615 var ac = ea.Expr.Type as ArrayContainer;
10616 int rank = ea.Arguments.Count;
10617 if (ac.Rank != rank) {
10618 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10619 rank.ToString (), ac.Rank.ToString ());
10624 if (type.IsPointer) {
10625 if (ec.CurrentIterator != null) {
10626 UnsafeInsideIteratorError (ec, ea.Location);
10627 } else if (!ec.IsUnsafe) {
10628 UnsafeError (ec, ea.Location);
10632 if (conditional_access_receiver)
10633 type = LiftMemberType (ec, type);
10635 foreach (Argument a in ea.Arguments) {
10636 var na = a as NamedArgument;
10638 ElementAccess.Error_NamedArgument (na, ec.Report);
10640 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10643 eclass = ExprClass.Variable;
10648 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10650 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10653 public override void FlowAnalysis (FlowAnalysisContext fc)
10655 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10657 ea.FlowAnalysis (fc);
10659 if (conditional_access_receiver)
10660 fc.DefiniteAssignment = da;
10663 public override bool HasConditionalAccess ()
10665 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10669 // Load the array arguments into the stack.
10671 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10673 if (prepareAwait) {
10674 ea.Expr = ea.Expr.EmitToField (ec);
10676 var ie = new InstanceEmitter (ea.Expr, false);
10677 ie.Emit (ec, ConditionalAccess);
10679 if (duplicateArguments) {
10680 ec.Emit (OpCodes.Dup);
10682 var copy = new LocalTemporary (ea.Expr.Type);
10688 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10689 if (dup_args != null)
10690 ea.Arguments = dup_args;
10693 public void Emit (EmitContext ec, bool leave_copy)
10696 ec.EmitLoadFromPtr (type);
10698 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10699 LoadInstanceAndArguments (ec, false, true);
10702 if (conditional_access_receiver)
10703 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10705 var ac = (ArrayContainer) ea.Expr.Type;
10706 LoadInstanceAndArguments (ec, false, false);
10707 ec.EmitArrayLoad (ac);
10709 if (conditional_access_receiver)
10710 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10714 ec.Emit (OpCodes.Dup);
10715 temp = new LocalTemporary (this.type);
10720 public override void Emit (EmitContext ec)
10725 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10727 var ac = (ArrayContainer) ea.Expr.Type;
10728 TypeSpec t = source.Type;
10730 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10733 // When we are dealing with a struct, get the address of it to avoid value copy
10734 // Same cannot be done for reference type because array covariance and the
10735 // check in ldelema requires to specify the type of array element stored at the index
10737 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10738 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10740 if (has_await_args.Value) {
10741 if (source.ContainsEmitWithAwait ()) {
10742 source = source.EmitToField (ec);
10743 isCompound = false;
10747 LoadInstanceAndArguments (ec, isCompound, false);
10752 ec.EmitArrayAddress (ac);
10755 ec.Emit (OpCodes.Dup);
10759 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10761 if (has_await_args.Value) {
10762 if (source.ContainsEmitWithAwait ())
10763 source = source.EmitToField (ec);
10765 LoadInstanceAndArguments (ec, false, false);
10772 var lt = ea.Expr as LocalTemporary;
10778 ec.Emit (OpCodes.Dup);
10779 temp = new LocalTemporary (this.type);
10784 ec.EmitStoreFromPtr (t);
10786 ec.EmitArrayStore (ac);
10789 if (temp != null) {
10795 public override Expression EmitToField (EmitContext ec)
10798 // Have to be specialized for arrays to get access to
10799 // underlying element. Instead of another result copy we
10800 // need direct access to element
10804 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10806 ea.Expr = ea.Expr.EmitToField (ec);
10807 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10811 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10813 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10816 public override SLE.Expression MakeExpression (BuilderContext ctx)
10818 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10821 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10823 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10824 return Arguments.MakeExpression (ea.Arguments, ctx);
10828 public void SetConditionalAccessReceiver ()
10830 conditional_access_receiver = true;
10835 // Indexer access expression
10837 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10839 IList<MemberSpec> indexers;
10840 Arguments arguments;
10841 TypeSpec queried_type;
10843 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10844 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10848 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10851 this.indexers = indexers;
10852 this.queried_type = queriedType;
10853 this.InstanceExpression = instance;
10854 this.arguments = args;
10859 protected override Arguments Arguments {
10868 protected override TypeSpec DeclaringType {
10870 return best_candidate.DeclaringType;
10874 public override bool IsInstance {
10880 public override bool IsStatic {
10886 public override string KindName {
10887 get { return "indexer"; }
10890 public override string Name {
10898 public override bool ContainsEmitWithAwait ()
10900 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10903 public override Expression CreateExpressionTree (ResolveContext ec)
10905 if (ConditionalAccess) {
10906 Error_NullShortCircuitInsideExpressionTree (ec);
10909 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10910 InstanceExpression.CreateExpressionTree (ec),
10911 new TypeOfMethod (Getter, loc));
10913 return CreateExpressionFactoryCall (ec, "Call", args);
10916 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10918 LocalTemporary await_source_arg = null;
10921 emitting_compound_assignment = true;
10922 if (source is DynamicExpressionStatement) {
10927 emitting_compound_assignment = false;
10929 if (has_await_arguments) {
10930 await_source_arg = new LocalTemporary (Type);
10931 await_source_arg.Store (ec);
10933 arguments.Add (new Argument (await_source_arg));
10936 temp = await_source_arg;
10939 has_await_arguments = false;
10944 ec.Emit (OpCodes.Dup);
10945 temp = new LocalTemporary (Type);
10951 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10952 source = source.EmitToField (ec);
10954 temp = new LocalTemporary (Type);
10961 arguments.Add (new Argument (source));
10964 var call = new CallEmitter ();
10965 call.InstanceExpression = InstanceExpression;
10966 if (arguments == null)
10967 call.InstanceExpressionOnStack = true;
10969 call.Emit (ec, Setter, arguments, loc);
10971 if (temp != null) {
10974 } else if (leave_copy) {
10978 if (await_source_arg != null) {
10979 await_source_arg.Release (ec);
10983 public override void FlowAnalysis (FlowAnalysisContext fc)
10985 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10987 base.FlowAnalysis (fc);
10988 arguments.FlowAnalysis (fc);
10990 if (conditional_access_receiver)
10991 fc.DefiniteAssignment = da;
10994 public override string GetSignatureForError ()
10996 return best_candidate.GetSignatureForError ();
10999 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
11002 throw new NotSupportedException ();
11004 var value = new[] { source.MakeExpression (ctx) };
11005 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
11006 return SLE.Expression.Block (
11007 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
11012 public override SLE.Expression MakeExpression (BuilderContext ctx)
11015 return base.MakeExpression (ctx);
11017 var args = Arguments.MakeExpression (arguments, ctx);
11018 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
11022 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
11024 if (best_candidate != null)
11027 eclass = ExprClass.IndexerAccess;
11030 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
11031 arguments.Resolve (rc, out dynamic);
11034 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11037 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
11038 res.BaseMembersProvider = this;
11039 res.InstanceQualifier = this;
11041 // TODO: Do I need 2 argument sets?
11042 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
11043 if (best_candidate != null)
11044 type = res.BestCandidateReturnType;
11045 else if (!res.BestCandidateIsDynamic)
11050 // It has dynamic arguments
11053 Arguments args = new Arguments (arguments.Count + 1);
11055 rc.Report.Error (1972, loc,
11056 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
11058 args.Add (new Argument (InstanceExpression));
11060 args.AddRange (arguments);
11062 best_candidate = null;
11063 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11067 // Try to avoid resolving left expression again
11069 if (right_side != null)
11070 ResolveInstanceExpression (rc, right_side);
11075 protected override void CloneTo (CloneContext clonectx, Expression t)
11077 IndexerExpr target = (IndexerExpr) t;
11079 if (arguments != null)
11080 target.arguments = arguments.Clone (clonectx);
11083 public void SetConditionalAccessReceiver ()
11085 conditional_access_receiver = true;
11088 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11090 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11093 #region IBaseMembersProvider Members
11095 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11097 var baseType = type.BaseType;
11098 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11100 if (members == null && !type.IsInterface) {
11101 var tps = queried_type as TypeParameterSpec;
11103 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11109 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11111 if (queried_type == member.DeclaringType)
11114 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11115 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11118 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11127 // A base access expression
11129 public class BaseThis : This
11131 public BaseThis (Location loc)
11136 public BaseThis (TypeSpec type, Location loc)
11140 eclass = ExprClass.Variable;
11145 public override string Name {
11153 public override Expression CreateExpressionTree (ResolveContext ec)
11155 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11156 return base.CreateExpressionTree (ec);
11159 public override void Emit (EmitContext ec)
11163 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11164 var context_type = ec.CurrentType;
11165 ec.Emit (OpCodes.Ldobj, context_type);
11166 ec.Emit (OpCodes.Box, context_type);
11170 protected override void Error_ThisNotAvailable (ResolveContext ec)
11173 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11175 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11179 public override void ResolveBase (ResolveContext ec)
11181 base.ResolveBase (ec);
11182 type = ec.CurrentType.BaseType;
11185 public override object Accept (StructuralVisitor visitor)
11187 return visitor.Visit (this);
11192 /// This class exists solely to pass the Type around and to be a dummy
11193 /// that can be passed to the conversion functions (this is used by
11194 /// foreach implementation to typecast the object return value from
11195 /// get_Current into the proper type. All code has been generated and
11196 /// we only care about the side effect conversions to be performed
11198 /// This is also now used as a placeholder where a no-action expression
11199 /// is needed (the `New' class).
11201 public class EmptyExpression : Expression
11203 sealed class OutAccessExpression : EmptyExpression
11205 public OutAccessExpression (TypeSpec t)
11210 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11212 rc.Report.Error (206, right_side.Location,
11213 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11219 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11220 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11221 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11222 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11223 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11224 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11225 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11226 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11228 public EmptyExpression (TypeSpec t)
11231 eclass = ExprClass.Value;
11232 loc = Location.Null;
11235 protected override void CloneTo (CloneContext clonectx, Expression target)
11239 public override bool ContainsEmitWithAwait ()
11244 public override Expression CreateExpressionTree (ResolveContext ec)
11246 throw new NotSupportedException ("ET");
11249 protected override Expression DoResolve (ResolveContext ec)
11254 public override void Emit (EmitContext ec)
11256 // nothing, as we only exist to not do anything.
11259 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11263 public override void EmitSideEffect (EmitContext ec)
11267 public override object Accept (StructuralVisitor visitor)
11269 return visitor.Visit (this);
11273 sealed class EmptyAwaitExpression : EmptyExpression
11275 public EmptyAwaitExpression (TypeSpec type)
11280 public override bool ContainsEmitWithAwait ()
11287 // Empty statement expression
11289 public sealed class EmptyExpressionStatement : ExpressionStatement
11291 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11293 private EmptyExpressionStatement ()
11295 loc = Location.Null;
11298 public override bool ContainsEmitWithAwait ()
11303 public override Expression CreateExpressionTree (ResolveContext ec)
11308 public override void EmitStatement (EmitContext ec)
11313 protected override Expression DoResolve (ResolveContext ec)
11315 eclass = ExprClass.Value;
11316 type = ec.BuiltinTypes.Object;
11320 public override void Emit (EmitContext ec)
11325 public override object Accept (StructuralVisitor visitor)
11327 return visitor.Visit (this);
11331 public class ErrorExpression : EmptyExpression
11333 public static readonly ErrorExpression Instance = new ErrorExpression ();
11335 private ErrorExpression ()
11336 : base (InternalType.ErrorType)
11340 public override Expression CreateExpressionTree (ResolveContext ec)
11345 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11350 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11354 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11358 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11362 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11366 public override object Accept (StructuralVisitor visitor)
11368 return visitor.Visit (this);
11372 public class UserCast : Expression {
11376 public UserCast (MethodSpec method, Expression source, Location l)
11378 if (source == null)
11379 throw new ArgumentNullException ("source");
11381 this.method = method;
11382 this.source = source;
11383 type = method.ReturnType;
11387 public Expression Source {
11396 public override bool ContainsEmitWithAwait ()
11398 return source.ContainsEmitWithAwait ();
11401 public override Expression CreateExpressionTree (ResolveContext ec)
11403 Arguments args = new Arguments (3);
11404 args.Add (new Argument (source.CreateExpressionTree (ec)));
11405 args.Add (new Argument (new TypeOf (type, loc)));
11406 args.Add (new Argument (new TypeOfMethod (method, loc)));
11407 return CreateExpressionFactoryCall (ec, "Convert", args);
11410 protected override Expression DoResolve (ResolveContext ec)
11412 method.CheckObsoleteness (ec, source.Location);
11414 eclass = ExprClass.Value;
11418 public override void Emit (EmitContext ec)
11421 ec.MarkCallEntry (loc);
11422 ec.Emit (OpCodes.Call, method);
11425 public override void FlowAnalysis (FlowAnalysisContext fc)
11427 source.FlowAnalysis (fc);
11430 public override string GetSignatureForError ()
11432 return TypeManager.CSharpSignature (method);
11435 public override SLE.Expression MakeExpression (BuilderContext ctx)
11438 return base.MakeExpression (ctx);
11440 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11446 // Holds additional type specifiers like ?, *, []
11448 public class ComposedTypeSpecifier
11450 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11452 public readonly int Dimension;
11453 public readonly Location Location;
11455 public ComposedTypeSpecifier (int specifier, Location loc)
11457 this.Dimension = specifier;
11458 this.Location = loc;
11462 public bool IsNullable {
11464 return Dimension == -1;
11468 public bool IsPointer {
11470 return Dimension == -2;
11474 public ComposedTypeSpecifier Next { get; set; }
11478 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11480 return new ComposedTypeSpecifier (dimension, loc);
11483 public static ComposedTypeSpecifier CreateNullable (Location loc)
11485 return new ComposedTypeSpecifier (-1, loc);
11488 public static ComposedTypeSpecifier CreatePointer (Location loc)
11490 return new ComposedTypeSpecifier (-2, loc);
11493 public string GetSignatureForError ()
11498 ArrayContainer.GetPostfixSignature (Dimension);
11500 return Next != null ? s + Next.GetSignatureForError () : s;
11505 // This class is used to "construct" the type during a typecast
11506 // operation. Since the Type.GetType class in .NET can parse
11507 // the type specification, we just use this to construct the type
11508 // one bit at a time.
11510 public class ComposedCast : TypeExpr {
11511 FullNamedExpression left;
11512 ComposedTypeSpecifier spec;
11514 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11517 throw new ArgumentNullException ("spec");
11521 this.loc = left.Location;
11524 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11526 type = left.ResolveAsType (ec);
11530 eclass = ExprClass.Type;
11532 var single_spec = spec;
11534 if (single_spec.IsNullable) {
11535 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11539 single_spec = single_spec.Next;
11540 } else if (single_spec.IsPointer) {
11542 // Declared fields cannot have unmanaged check done before all types are defined
11544 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11547 var rc = ec as ResolveContext;
11548 if (rc?.CurrentIterator != null) {
11549 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11550 } else if (!ec.IsUnsafe) {
11551 UnsafeError (ec.Module.Compiler.Report, loc);
11555 type = PointerContainer.MakeType (ec.Module, type);
11556 single_spec = single_spec.Next;
11557 } while (single_spec != null && single_spec.IsPointer);
11560 if (single_spec != null && single_spec.Dimension > 0) {
11561 if (type.IsSpecialRuntimeType) {
11562 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11563 } else if (type.IsStatic) {
11564 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11565 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11566 type.GetSignatureForError ());
11568 MakeArray (ec.Module, single_spec);
11575 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11577 if (spec.Next != null)
11578 MakeArray (module, spec.Next);
11580 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11583 public override string GetSignatureForError ()
11585 return left.GetSignatureForError () + spec.GetSignatureForError ();
11588 public override object Accept (StructuralVisitor visitor)
11590 return visitor.Visit (this);
11594 class FixedBufferPtr : Expression
11596 readonly Expression array;
11598 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11600 this.type = array_type;
11601 this.array = array;
11605 public override bool ContainsEmitWithAwait ()
11607 throw new NotImplementedException ();
11610 public override Expression CreateExpressionTree (ResolveContext ec)
11612 Error_PointerInsideExpressionTree (ec);
11616 public override void Emit(EmitContext ec)
11621 protected override Expression DoResolve (ResolveContext ec)
11623 type = PointerContainer.MakeType (ec.Module, type);
11624 eclass = ExprClass.Value;
11631 // This class is used to represent the address of an array, used
11632 // only by the Fixed statement, this generates "&a [0]" construct
11633 // for fixed (char *pa = a)
11635 class ArrayPtr : FixedBufferPtr
11637 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11638 base (array, array_type, l)
11642 public override void Emit (EmitContext ec)
11647 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11652 // Encapsulates a conversion rules required for array indexes
11654 public class ArrayIndexCast : TypeCast
11656 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11657 : base (expr, returnType)
11659 if (expr.Type == returnType) // int -> int
11660 throw new ArgumentException ("unnecessary array index conversion");
11663 public override Expression CreateExpressionTree (ResolveContext ec)
11665 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11666 return base.CreateExpressionTree (ec);
11670 public override void Emit (EmitContext ec)
11674 switch (child.Type.BuiltinType) {
11675 case BuiltinTypeSpec.Type.UInt:
11676 ec.Emit (OpCodes.Conv_U);
11678 case BuiltinTypeSpec.Type.Long:
11679 ec.Emit (OpCodes.Conv_Ovf_I);
11681 case BuiltinTypeSpec.Type.ULong:
11682 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11685 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11691 // Implements the `stackalloc' keyword
11693 public class StackAlloc : Expression {
11698 public StackAlloc (Expression type, Expression count, Location l)
11701 this.count = count;
11705 public Expression TypeExpression {
11711 public Expression CountExpression {
11717 public override bool ContainsEmitWithAwait ()
11722 public override Expression CreateExpressionTree (ResolveContext ec)
11724 throw new NotSupportedException ("ET");
11727 protected override Expression DoResolve (ResolveContext ec)
11729 count = count.Resolve (ec);
11733 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11734 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11739 Constant c = count as Constant;
11740 if (c != null && c.IsNegative) {
11741 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11744 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11745 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11748 otype = texpr.ResolveAsType (ec);
11752 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11755 type = PointerContainer.MakeType (ec.Module, otype);
11756 eclass = ExprClass.Value;
11761 public override void Emit (EmitContext ec)
11763 int size = BuiltinTypeSpec.GetSize (otype);
11768 ec.Emit (OpCodes.Sizeof, otype);
11772 ec.Emit (OpCodes.Mul_Ovf_Un);
11773 ec.Emit (OpCodes.Localloc);
11776 protected override void CloneTo (CloneContext clonectx, Expression t)
11778 StackAlloc target = (StackAlloc) t;
11779 target.count = count.Clone (clonectx);
11780 target.texpr = texpr.Clone (clonectx);
11783 public override object Accept (StructuralVisitor visitor)
11785 return visitor.Visit (this);
11790 // An object initializer expression
11792 public class ElementInitializer : Assign
11794 public readonly string Name;
11796 public ElementInitializer (string name, Expression initializer, Location loc)
11797 : base (null, initializer, loc)
11802 public bool IsDictionaryInitializer {
11804 return Name == null;
11808 protected override void CloneTo (CloneContext clonectx, Expression t)
11810 ElementInitializer target = (ElementInitializer) t;
11811 target.source = source.Clone (clonectx);
11814 public override Expression CreateExpressionTree (ResolveContext ec)
11816 Arguments args = new Arguments (2);
11817 FieldExpr fe = target as FieldExpr;
11819 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11821 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11824 Expression arg_expr;
11825 var cinit = source as CollectionOrObjectInitializers;
11826 if (cinit == null) {
11828 arg_expr = source.CreateExpressionTree (ec);
11830 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11831 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11834 args.Add (new Argument (arg_expr));
11835 return CreateExpressionFactoryCall (ec, mname, args);
11838 protected override Expression DoResolve (ResolveContext ec)
11840 if (source == null)
11841 return EmptyExpressionStatement.Instance;
11843 if (!ResolveElement (ec))
11846 if (source is CollectionOrObjectInitializers) {
11847 target = target.Resolve (ec);
11848 if (target == null)
11851 Expression previous = ec.CurrentInitializerVariable;
11852 ec.CurrentInitializerVariable = target;
11853 source = source.Resolve (ec);
11854 ec.CurrentInitializerVariable = previous;
11855 if (source == null)
11858 eclass = source.eclass;
11859 type = source.Type;
11864 return base.DoResolve (ec);
11867 public override void EmitStatement (EmitContext ec)
11869 if (source is CollectionOrObjectInitializers)
11872 base.EmitStatement (ec);
11875 protected virtual bool ResolveElement (ResolveContext rc)
11877 var t = rc.CurrentInitializerVariable.Type;
11878 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11879 Arguments args = new Arguments (1);
11880 args.Add (new Argument (rc.CurrentInitializerVariable));
11881 target = new DynamicMemberBinder (Name, args, loc);
11883 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11884 if (member == null) {
11885 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11887 if (member != null) {
11888 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11889 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11894 if (member == null) {
11895 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11899 var me = member as MemberExpr;
11900 if (me is EventExpr) {
11901 me = me.ResolveMemberAccess (rc, null, null);
11902 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11903 rc.Report.Error (1913, loc,
11904 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11905 member.GetSignatureForError ());
11911 rc.Report.Error (1914, loc,
11912 "Static field or property `{0}' cannot be assigned in an object initializer",
11913 me.GetSignatureForError ());
11917 me.InstanceExpression = rc.CurrentInitializerVariable;
11925 // A collection initializer expression
11927 class CollectionElementInitializer : Invocation
11929 public class ElementInitializerArgument : Argument
11931 public ElementInitializerArgument (Expression e)
11937 sealed class AddMemberAccess : MemberAccess
11939 public AddMemberAccess (Expression expr, Location loc)
11940 : base (expr, "Add", loc)
11944 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11946 if (TypeManager.HasElementType (type))
11949 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11953 public CollectionElementInitializer (Expression argument)
11954 : base (null, new Arguments (1))
11956 base.arguments.Add (new ElementInitializerArgument (argument));
11957 this.loc = argument.Location;
11960 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11961 : base (null, new Arguments (arguments.Count))
11963 foreach (Expression e in arguments)
11964 base.arguments.Add (new ElementInitializerArgument (e));
11969 public CollectionElementInitializer (Location loc)
11970 : base (null, null)
11975 public override Expression CreateExpressionTree (ResolveContext ec)
11977 Arguments args = new Arguments (2);
11978 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11980 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11981 foreach (Argument a in arguments) {
11982 if (a.ArgType == Argument.AType.ExtensionType) {
11983 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11986 expr_initializers.Add (a.CreateExpressionTree (ec));
11989 args.Add (new Argument (new ArrayCreation (
11990 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11991 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11994 protected override void CloneTo (CloneContext clonectx, Expression t)
11996 CollectionElementInitializer target = (CollectionElementInitializer) t;
11997 if (arguments != null)
11998 target.arguments = arguments.Clone (clonectx);
12001 protected override Expression DoResolve (ResolveContext ec)
12003 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
12005 return base.DoResolve (ec);
12009 class DictionaryElementInitializer : ElementInitializer
12011 readonly Arguments args;
12013 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
12014 : base (null, initializer, loc)
12016 this.args = arguments;
12019 public override Expression CreateExpressionTree (ResolveContext ec)
12021 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
12025 protected override bool ResolveElement (ResolveContext rc)
12027 var init = rc.CurrentInitializerVariable;
12028 var type = init.Type;
12030 if (type.IsArray) {
12031 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
12035 if (type.IsPointer) {
12036 target = init.MakePointerAccess (rc, type, args);
12040 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
12041 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12042 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
12046 target = new IndexerExpr (indexers, type, init, args, loc);
12052 // A block of object or collection initializers
12054 public class CollectionOrObjectInitializers : ExpressionStatement
12056 IList<Expression> initializers;
12057 bool is_collection_initialization;
12059 public CollectionOrObjectInitializers (Location loc)
12060 : this (new Expression[0], loc)
12064 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12066 this.initializers = initializers;
12070 public IList<Expression> Initializers {
12072 return initializers;
12076 public bool IsEmpty {
12078 return initializers.Count == 0;
12082 public bool IsCollectionInitializer {
12084 return is_collection_initialization;
12088 protected override void CloneTo (CloneContext clonectx, Expression target)
12090 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12092 t.initializers = new List<Expression> (initializers.Count);
12093 foreach (var e in initializers)
12094 t.initializers.Add (e.Clone (clonectx));
12097 public override bool ContainsEmitWithAwait ()
12099 foreach (var e in initializers) {
12100 if (e.ContainsEmitWithAwait ())
12107 public override Expression CreateExpressionTree (ResolveContext ec)
12109 return CreateExpressionTree (ec, false);
12112 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12114 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12115 foreach (Expression e in initializers) {
12116 Expression expr = e.CreateExpressionTree (ec);
12118 expr_initializers.Add (expr);
12122 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12124 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12127 protected override Expression DoResolve (ResolveContext ec)
12129 List<string> element_names = null;
12130 for (int i = 0; i < initializers.Count; ++i) {
12131 Expression initializer = initializers [i];
12132 ElementInitializer element_initializer = initializer as ElementInitializer;
12135 if (element_initializer != null) {
12136 element_names = new List<string> (initializers.Count);
12137 if (!element_initializer.IsDictionaryInitializer)
12138 element_names.Add (element_initializer.Name);
12139 } else if (initializer is CompletingExpression) {
12140 initializer.Resolve (ec);
12141 throw new InternalErrorException ("This line should never be reached");
12143 var t = ec.CurrentInitializerVariable.Type;
12144 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12145 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12146 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12147 "object initializer because type `{1}' does not implement `{2}' interface",
12148 ec.CurrentInitializerVariable.GetSignatureForError (),
12149 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12150 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12153 is_collection_initialization = true;
12156 if (is_collection_initialization != (element_initializer == null)) {
12157 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12158 is_collection_initialization ? "collection initializer" : "object initializer");
12162 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12163 if (element_names.Contains (element_initializer.Name)) {
12164 ec.Report.Error (1912, element_initializer.Location,
12165 "An object initializer includes more than one member `{0}' initialization",
12166 element_initializer.Name);
12168 element_names.Add (element_initializer.Name);
12173 Expression e = initializer.Resolve (ec);
12174 if (e == EmptyExpressionStatement.Instance)
12175 initializers.RemoveAt (i--);
12177 initializers [i] = e;
12180 type = ec.CurrentInitializerVariable.Type;
12181 if (is_collection_initialization) {
12182 if (TypeManager.HasElementType (type)) {
12183 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12184 type.GetSignatureForError ());
12188 eclass = ExprClass.Variable;
12192 public override void Emit (EmitContext ec)
12194 EmitStatement (ec);
12197 public override void EmitStatement (EmitContext ec)
12199 foreach (ExpressionStatement e in initializers) {
12200 // TODO: need location region
12201 ec.Mark (e.Location);
12202 e.EmitStatement (ec);
12206 public override void FlowAnalysis (FlowAnalysisContext fc)
12208 foreach (var initializer in initializers) {
12209 if (initializer != null)
12210 initializer.FlowAnalysis (fc);
12216 // New expression with element/object initializers
12218 public class NewInitialize : New
12221 // This class serves as a proxy for variable initializer target instances.
12222 // A real variable is assigned later when we resolve left side of an
12225 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12227 NewInitialize new_instance;
12229 public InitializerTargetExpression (NewInitialize newInstance)
12231 this.type = newInstance.type;
12232 this.loc = newInstance.loc;
12233 this.eclass = newInstance.eclass;
12234 this.new_instance = newInstance;
12237 public override bool ContainsEmitWithAwait ()
12242 public override Expression CreateExpressionTree (ResolveContext ec)
12244 // Should not be reached
12245 throw new NotSupportedException ("ET");
12248 protected override Expression DoResolve (ResolveContext ec)
12253 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12258 public override void Emit (EmitContext ec)
12260 Expression e = (Expression) new_instance.instance;
12264 public override Expression EmitToField (EmitContext ec)
12266 return (Expression) new_instance.instance;
12269 #region IMemoryLocation Members
12271 public void AddressOf (EmitContext ec, AddressOp mode)
12273 new_instance.instance.AddressOf (ec, mode);
12279 CollectionOrObjectInitializers initializers;
12280 IMemoryLocation instance;
12281 DynamicExpressionStatement dynamic;
12283 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12284 : base (requested_type, arguments, l)
12286 this.initializers = initializers;
12289 public CollectionOrObjectInitializers Initializers {
12291 return initializers;
12295 protected override void CloneTo (CloneContext clonectx, Expression t)
12297 base.CloneTo (clonectx, t);
12299 NewInitialize target = (NewInitialize) t;
12300 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12303 public override bool ContainsEmitWithAwait ()
12305 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12308 public override Expression CreateExpressionTree (ResolveContext ec)
12310 Arguments args = new Arguments (2);
12311 args.Add (new Argument (base.CreateExpressionTree (ec)));
12312 if (!initializers.IsEmpty)
12313 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12315 return CreateExpressionFactoryCall (ec,
12316 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12320 protected override Expression DoResolve (ResolveContext rc)
12322 Expression e = base.DoResolve (rc);
12326 if (type.IsDelegate) {
12327 rc.Report.Error (1958, Initializers.Location,
12328 "Object and collection initializers cannot be used to instantiate a delegate");
12331 Expression previous = rc.CurrentInitializerVariable;
12332 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12333 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12334 initializers.Resolve (rc);
12336 rc.CurrentInitializerVariable = previous;
12338 dynamic = e as DynamicExpressionStatement;
12339 if (dynamic != null)
12345 public override void Emit (EmitContext ec)
12347 if (!CanEmitOptimizedLocalTarget (ec)) {
12348 var fe = ec.GetTemporaryField (type);
12350 if (!Emit (ec, fe))
12359 public override bool Emit (EmitContext ec, IMemoryLocation target)
12362 // Expression is initialized into temporary target then moved
12363 // to real one for atomicity
12365 IMemoryLocation temp_target = target;
12367 LocalTemporary temp = null;
12368 bool by_ref = false;
12369 if (!initializers.IsEmpty) {
12370 temp_target = target as LocalTemporary;
12371 if (temp_target == null)
12372 temp_target = target as StackFieldExpr;
12374 if (temp_target == null) {
12375 var vr = target as VariableReference;
12376 if (vr != null && vr.IsRef) {
12382 if (temp_target == null)
12383 temp_target = temp = new LocalTemporary (type);
12386 bool left_on_stack;
12387 if (dynamic != null) {
12389 left_on_stack = true;
12391 left_on_stack = base.Emit (ec, temp_target);
12394 if (initializers.IsEmpty)
12395 return left_on_stack;
12397 StackFieldExpr sf = null;
12399 // Move a new instance (reference-type) to local temporary variable
12400 if (left_on_stack) {
12402 temp_target = temp = new LocalTemporary (type);
12408 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12410 throw new NotImplementedException ();
12412 sf = ec.GetTemporaryField (type);
12413 sf.AutomaticallyReuse = false;
12414 sf.EmitAssign (ec, temp, false, false);
12417 left_on_stack = false;
12421 instance = temp_target;
12423 initializers.Emit (ec);
12425 ((Expression)temp_target).Emit (ec);
12431 sf.PrepareCleanup (ec);
12436 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12438 return !(method == null && TypeSpec.IsValueType (type) &&
12439 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12440 initializers.ContainsEmitWithAwait ());
12443 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12445 instance = base.EmitAddressOf (ec, Mode);
12447 if (!initializers.IsEmpty)
12448 initializers.Emit (ec);
12453 public override void FlowAnalysis (FlowAnalysisContext fc)
12455 base.FlowAnalysis (fc);
12456 initializers.FlowAnalysis (fc);
12459 public override object Accept (StructuralVisitor visitor)
12461 return visitor.Visit (this);
12465 public class NewAnonymousType : New
12467 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12469 List<AnonymousTypeParameter> parameters;
12470 readonly TypeContainer parent;
12471 AnonymousTypeClass anonymous_type;
12473 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12474 : base (null, null, loc)
12476 this.parameters = parameters;
12477 this.parent = parent;
12480 public List<AnonymousTypeParameter> Parameters {
12482 return this.parameters;
12486 protected override void CloneTo (CloneContext clonectx, Expression target)
12488 if (parameters == null)
12491 NewAnonymousType t = (NewAnonymousType) target;
12492 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12493 foreach (AnonymousTypeParameter atp in parameters)
12494 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12497 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12499 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12503 type = AnonymousTypeClass.Create (parent, parameters, loc);
12507 int errors = ec.Report.Errors;
12508 type.CreateContainer ();
12509 type.DefineContainer ();
12510 type.ExpandBaseInterfaces ();
12512 if ((ec.Report.Errors - errors) == 0) {
12513 parent.Module.AddAnonymousType (type);
12514 type.PrepareEmit ();
12520 public override Expression CreateExpressionTree (ResolveContext ec)
12522 if (parameters == null)
12523 return base.CreateExpressionTree (ec);
12525 var init = new ArrayInitializer (parameters.Count, loc);
12526 foreach (var m in anonymous_type.Members) {
12527 var p = m as Property;
12529 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12532 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12533 foreach (Argument a in arguments)
12534 ctor_args.Add (a.CreateExpressionTree (ec));
12536 Arguments args = new Arguments (3);
12537 args.Add (new Argument (new TypeOfMethod (method, loc)));
12538 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12539 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12541 return CreateExpressionFactoryCall (ec, "New", args);
12544 protected override Expression DoResolve (ResolveContext ec)
12546 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12547 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12551 if (parameters == null) {
12552 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12553 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12554 return base.DoResolve (ec);
12557 bool error = false;
12558 arguments = new Arguments (parameters.Count);
12559 var t_args = new TypeSpec [parameters.Count];
12560 for (int i = 0; i < parameters.Count; ++i) {
12561 Expression e = parameters [i].Resolve (ec);
12567 arguments.Add (new Argument (e));
12568 t_args [i] = e.Type;
12574 anonymous_type = CreateAnonymousType (ec, parameters);
12575 if (anonymous_type == null)
12578 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12579 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12580 eclass = ExprClass.Value;
12584 public override object Accept (StructuralVisitor visitor)
12586 return visitor.Visit (this);
12590 public class AnonymousTypeParameter : ShimExpression
12592 public readonly string Name;
12594 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12595 : base (initializer)
12601 public AnonymousTypeParameter (Parameter parameter)
12602 : base (new SimpleName (parameter.Name, parameter.Location))
12604 this.Name = parameter.Name;
12605 this.loc = parameter.Location;
12608 public override bool Equals (object o)
12610 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12611 return other != null && Name == other.Name;
12614 public override int GetHashCode ()
12616 return Name.GetHashCode ();
12619 protected override Expression DoResolve (ResolveContext ec)
12621 Expression e = expr.Resolve (ec);
12625 if (e.eclass == ExprClass.MethodGroup) {
12626 Error_InvalidInitializer (ec, e.ExprClassName);
12631 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
12632 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12639 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12641 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12642 Name, initializer);
12646 public class CatchFilterExpression : BooleanExpression
12648 public CatchFilterExpression (Expression expr, Location loc)
12655 public class InterpolatedString : Expression
12657 readonly StringLiteral start, end;
12658 List<Expression> interpolations;
12659 Arguments arguments;
12661 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12663 this.start = start;
12665 this.interpolations = interpolations;
12666 loc = start.Location;
12669 protected override void CloneTo (CloneContext clonectx, Expression t)
12671 InterpolatedString target = (InterpolatedString) t;
12673 if (interpolations != null) {
12674 target.interpolations = new List<Expression> ();
12675 foreach (var interpolation in interpolations) {
12676 target.interpolations.Add (interpolation.Clone (clonectx));
12681 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12683 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12684 if (factory == null)
12687 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12688 var res = new Invocation (ma, arguments).Resolve (rc);
12689 if (res != null && res.Type != type)
12690 res = Convert.ExplicitConversion (rc, res, type, loc);
12695 public override bool ContainsEmitWithAwait ()
12697 if (interpolations == null)
12700 foreach (var expr in interpolations) {
12701 if (expr.ContainsEmitWithAwait ())
12708 public override Expression CreateExpressionTree (ResolveContext rc)
12710 var best = ResolveBestFormatOverload (rc);
12714 Expression instance = new NullLiteral (loc);
12715 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12716 return CreateExpressionFactoryCall (rc, "Call", args);
12719 protected override Expression DoResolve (ResolveContext rc)
12723 if (interpolations == null) {
12725 arguments = new Arguments (1);
12727 arguments = new Arguments (interpolations.Count);
12729 var sb = new StringBuilder (start.Value);
12730 for (int i = 0; i < interpolations.Count; ++i) {
12732 sb.Append ('{').Append (i / 2);
12733 var isi = (InterpolatedStringInsert)interpolations [i];
12734 if (isi.Alignment != null) {
12736 var value = isi.ResolveAligment (rc);
12738 sb.Append (value.Value);
12741 if (isi.Format != null) {
12743 sb.Append (isi.Format);
12747 arguments.Add (new Argument (isi.Resolve (rc)));
12749 sb.Append (((StringLiteral)interpolations [i]).Value);
12753 sb.Append (end.Value);
12754 str = sb.ToString ();
12757 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12759 eclass = ExprClass.Value;
12760 type = rc.BuiltinTypes.String;
12764 public override void Emit (EmitContext ec)
12766 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12767 if (interpolations == null) {
12768 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12769 if (str != start.Value)
12770 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12777 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12781 var ca = new CallEmitter ();
12782 ca.Emit (ec, best, arguments, loc);
12785 public override void FlowAnalysis (FlowAnalysisContext fc)
12787 if (interpolations != null) {
12788 foreach (var expr in interpolations) {
12789 expr.FlowAnalysis (fc);
12794 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12796 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12797 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12798 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12802 public class InterpolatedStringInsert : CompositeExpression
12804 public InterpolatedStringInsert (Expression expr)
12809 public Expression Alignment { get; set; }
12810 public string Format { get; set; }
12812 protected override void CloneTo (CloneContext clonectx, Expression t)
12814 var target = (InterpolatedStringInsert)t;
12815 target.expr = expr.Clone (clonectx);
12816 if (Alignment != null)
12817 target.Alignment = Alignment.Clone (clonectx);
12820 protected override Expression DoResolve (ResolveContext rc)
12822 var expr = base.DoResolve (rc);
12827 // For better error reporting, assumes the built-in implementation uses object
12830 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12833 public override void FlowAnalysis (FlowAnalysisContext fc)
12835 Child.FlowAnalysis (fc);
12838 public int? ResolveAligment (ResolveContext rc)
12840 var c = Alignment.ResolveLabelConstant (rc);
12844 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12848 var value = (int) c.GetValueAsLong ();
12849 if (value > 32767 || value < -32767) {
12850 rc.Report.Warning (8094, 1, Alignment.Location,
12851 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12858 class ThrowExpression : ExpressionStatement
12862 public ThrowExpression (Expression expr, Location loc)
12868 protected override void CloneTo (CloneContext clonectx, Expression t)
12870 var target = (ThrowExpression)t;
12871 target.expr = expr.Clone (clonectx);
12874 public override bool ContainsEmitWithAwait ()
12876 return expr.ContainsEmitWithAwait ();
12879 public override Expression CreateExpressionTree (ResolveContext rc)
12881 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12885 protected override Expression DoResolve (ResolveContext rc)
12887 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12892 expr = Throw.ConvertType (rc, expr);
12894 eclass = ExprClass.Value;
12895 type = InternalType.ThrowExpr;
12899 public override void Emit (EmitContext ec)
12901 EmitStatement (ec);
12904 public override void EmitStatement (EmitContext ec)
12908 ec.Emit (OpCodes.Throw);
12911 public override void FlowAnalysis (FlowAnalysisContext fc)
12913 expr.FlowAnalysis (fc);
12916 public override Reachability MarkReachable (Reachability rc)
12918 return Reachability.CreateUnreachable ();