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 Variable.CreateBuilder (ec);
2621 if (Initializer != null) {
2622 lvr.EmitAssign (ec, Initializer, false, false);
2625 lvr.AddressOf (ec, mode);
2628 protected override void CloneTo (CloneContext clonectx, Expression t)
2630 var target = (DeclarationExpression) t;
2632 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2634 if (Initializer != null)
2635 target.Initializer = Initializer.Clone (clonectx);
2638 public override Expression CreateExpressionTree (ResolveContext rc)
2640 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2644 bool DoResolveCommon (ResolveContext rc)
2646 CheckExpressionVariable (rc);
2648 var var_expr = VariableType as VarExpr;
2649 if (var_expr != null) {
2650 type = InternalType.VarOutType;
2652 type = VariableType.ResolveAsType (rc);
2657 if (Initializer != null) {
2658 Initializer = Initializer.Resolve (rc);
2660 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2661 type = var_expr.Type;
2665 Variable.Type = type;
2666 lvr = new LocalVariableReference (Variable, loc);
2668 eclass = ExprClass.Variable;
2672 protected override Expression DoResolve (ResolveContext rc)
2674 if (DoResolveCommon (rc))
2680 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2682 if (lvr == null && DoResolveCommon (rc))
2683 lvr.ResolveLValue (rc, right_side);
2688 public override void Emit (EmitContext ec)
2690 throw new NotImplementedException ();
2695 // C# 2.0 Default value expression
2697 public class DefaultValueExpression : Expression
2701 public DefaultValueExpression (Expression expr, Location loc)
2707 public Expression Expr {
2713 public override bool IsSideEffectFree {
2719 public override bool ContainsEmitWithAwait ()
2724 public override Expression CreateExpressionTree (ResolveContext ec)
2726 Arguments args = new Arguments (2);
2727 args.Add (new Argument (this));
2728 args.Add (new Argument (new TypeOf (type, loc)));
2729 return CreateExpressionFactoryCall (ec, "Constant", args);
2732 protected override Expression DoResolve (ResolveContext ec)
2734 type = expr.ResolveAsType (ec);
2738 if (type.IsStatic) {
2739 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2743 return new NullLiteral (Location).ConvertImplicitly (type);
2745 if (TypeSpec.IsReferenceType (type))
2746 return new NullConstant (type, loc);
2748 Constant c = New.Constantify (type, expr.Location);
2752 eclass = ExprClass.Variable;
2756 public override void Emit (EmitContext ec)
2758 LocalTemporary temp_storage = new LocalTemporary(type);
2760 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2761 ec.Emit(OpCodes.Initobj, type);
2762 temp_storage.Emit(ec);
2763 temp_storage.Release (ec);
2767 public override SLE.Expression MakeExpression (BuilderContext ctx)
2769 return SLE.Expression.Default (type.GetMetaInfo ());
2773 protected override void CloneTo (CloneContext clonectx, Expression t)
2775 DefaultValueExpression target = (DefaultValueExpression) t;
2777 target.expr = expr.Clone (clonectx);
2780 public override object Accept (StructuralVisitor visitor)
2782 return visitor.Visit (this);
2787 /// Binary operators
2789 public class Binary : Expression, IDynamicBinder
2791 public class PredefinedOperator
2793 protected readonly TypeSpec left;
2794 protected readonly TypeSpec right;
2795 protected readonly TypeSpec left_unwrap;
2796 protected readonly TypeSpec right_unwrap;
2797 public readonly Operator OperatorsMask;
2798 public TypeSpec ReturnType;
2800 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2801 : this (ltype, rtype, op_mask, ltype)
2805 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2806 : this (type, type, op_mask, return_type)
2810 public PredefinedOperator (TypeSpec type, Operator op_mask)
2811 : this (type, type, op_mask, type)
2815 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2817 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2818 throw new InternalErrorException ("Only masked values can be used");
2820 if ((op_mask & Operator.NullableMask) != 0) {
2821 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2822 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2824 left_unwrap = ltype;
2825 right_unwrap = rtype;
2830 this.OperatorsMask = op_mask;
2831 this.ReturnType = return_type;
2834 public bool IsLifted {
2836 return (OperatorsMask & Operator.NullableMask) != 0;
2840 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2844 var left_expr = b.left;
2845 var right_expr = b.right;
2847 b.type = ReturnType;
2850 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2851 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2852 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2855 if (right_expr.IsNull) {
2856 if ((b.oper & Operator.EqualityMask) != 0) {
2857 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2858 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2859 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2860 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2861 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2863 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2864 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2866 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2867 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2869 return b.CreateLiftedValueTypeResult (rc, left);
2871 } else if (left_expr.IsNull) {
2872 if ((b.oper & Operator.EqualityMask) != 0) {
2873 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2874 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2875 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2876 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2877 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2879 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2880 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2882 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2883 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2885 return b.CreateLiftedValueTypeResult (rc, right);
2891 // A user operators does not support multiple user conversions, but decimal type
2892 // is considered to be predefined type therefore we apply predefined operators rules
2893 // and then look for decimal user-operator implementation
2895 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2896 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2897 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2899 return b.ResolveUserOperator (rc, b.left, b.right);
2902 c = right_expr as Constant;
2904 if (c.IsDefaultValue) {
2908 // (expr + 0) to expr
2909 // (expr - 0) to expr
2910 // (bool? | false) to bool?
2912 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2913 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2914 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2915 return ReducedExpression.Create (b.left, b).Resolve (rc);
2919 // Optimizes (value &/&& 0) to 0
2921 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2922 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2923 return ReducedExpression.Create (side_effect, b);
2927 // Optimizes (bool? & true) to bool?
2929 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2930 return ReducedExpression.Create (b.left, b).Resolve (rc);
2934 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2935 return ReducedExpression.Create (b.left, b).Resolve (rc);
2937 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2938 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2942 c = b.left as Constant;
2944 if (c.IsDefaultValue) {
2948 // (0 + expr) to expr
2949 // (false | bool?) to bool?
2951 if (b.oper == Operator.Addition ||
2952 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2953 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2954 return ReducedExpression.Create (b.right, b).Resolve (rc);
2958 // Optimizes (false && expr) to false
2960 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2961 // No rhs side-effects
2962 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2963 return ReducedExpression.Create (c, b);
2967 // Optimizes (0 & value) to 0
2969 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2970 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2971 return ReducedExpression.Create (side_effect, b);
2975 // Optimizes (true & bool?) to bool?
2977 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2978 return ReducedExpression.Create (b.right, b).Resolve (rc);
2982 // Optimizes (true || expr) to true
2984 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2985 // No rhs side-effects
2986 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2987 return ReducedExpression.Create (c, b);
2991 if (b.oper == Operator.Multiply && c.IsOneInteger)
2992 return ReducedExpression.Create (b.right, b).Resolve (rc);
2996 var lifted = new Nullable.LiftedBinaryOperator (b);
2998 TypeSpec ltype, rtype;
2999 if (b.left.Type.IsNullableType) {
3000 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
3001 ltype = left_unwrap;
3006 if (b.right.Type.IsNullableType) {
3007 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
3008 rtype = right_unwrap;
3013 lifted.Left = b.left.IsNull ?
3014 Nullable.LiftedNull.Create (ltype, b.left.Location) :
3015 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
3017 lifted.Right = b.right.IsNull ?
3018 Nullable.LiftedNull.Create (rtype, b.right.Location) :
3019 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
3021 return lifted.Resolve (rc);
3024 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3025 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3030 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3033 // We are dealing with primitive types only
3035 return left == ltype && ltype == rtype;
3038 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3041 if (left == lexpr.Type && right == rexpr.Type)
3044 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3045 Convert.ImplicitConversionExists (ec, rexpr, right);
3048 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3050 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3051 return best_operator;
3053 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3057 if (left != null && best_operator.left != null) {
3058 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3062 // When second argument is same as the first one, the result is same
3064 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3065 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3068 if (result == 0 || result > 2)
3071 return result == 1 ? best_operator : this;
3075 sealed class PredefinedStringOperator : PredefinedOperator
3077 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3078 : base (type, type, op_mask, retType)
3082 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3083 : base (ltype, rtype, op_mask, retType)
3087 public override Expression ConvertResult (ResolveContext ec, Binary b)
3090 // Use original expression for nullable arguments
3092 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3094 b.left = unwrap.Original;
3096 unwrap = b.right as Nullable.Unwrap;
3098 b.right = unwrap.Original;
3100 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3101 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3104 // Start a new concat expression using converted expression
3106 return StringConcat.Create (ec, b.left, b.right, b.loc);
3110 sealed class PredefinedEqualityOperator : PredefinedOperator
3112 MethodSpec equal_method, inequal_method;
3114 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3115 : base (arg, arg, Operator.EqualityMask, retType)
3119 public override Expression ConvertResult (ResolveContext ec, Binary b)
3121 b.type = ReturnType;
3123 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3124 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3126 Arguments args = new Arguments (2);
3127 args.Add (new Argument (b.left));
3128 args.Add (new Argument (b.right));
3131 if (b.oper == Operator.Equality) {
3132 if (equal_method == null) {
3133 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3134 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3135 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3136 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3138 throw new NotImplementedException (left.GetSignatureForError ());
3141 method = equal_method;
3143 if (inequal_method == null) {
3144 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3145 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3146 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3147 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3149 throw new NotImplementedException (left.GetSignatureForError ());
3152 method = inequal_method;
3155 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3159 class PredefinedPointerOperator : PredefinedOperator
3161 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3162 : base (ltype, rtype, op_mask)
3166 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3167 : base (ltype, rtype, op_mask, retType)
3171 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3172 : base (type, op_mask, return_type)
3176 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3179 if (!lexpr.Type.IsPointer)
3182 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3186 if (right == null) {
3187 if (!rexpr.Type.IsPointer)
3190 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3197 public override Expression ConvertResult (ResolveContext ec, Binary b)
3200 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3201 } else if (right != null) {
3202 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3205 TypeSpec r_type = ReturnType;
3206 Expression left_arg, right_arg;
3207 if (r_type == null) {
3210 right_arg = b.right;
3211 r_type = b.left.Type;
3215 r_type = b.right.Type;
3219 right_arg = b.right;
3222 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3227 public enum Operator {
3228 Multiply = 0 | ArithmeticMask,
3229 Division = 1 | ArithmeticMask,
3230 Modulus = 2 | ArithmeticMask,
3231 Addition = 3 | ArithmeticMask | AdditionMask,
3232 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3234 LeftShift = 5 | ShiftMask,
3235 RightShift = 6 | ShiftMask,
3237 LessThan = 7 | ComparisonMask | RelationalMask,
3238 GreaterThan = 8 | ComparisonMask | RelationalMask,
3239 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3240 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3241 Equality = 11 | ComparisonMask | EqualityMask,
3242 Inequality = 12 | ComparisonMask | EqualityMask,
3244 BitwiseAnd = 13 | BitwiseMask,
3245 ExclusiveOr = 14 | BitwiseMask,
3246 BitwiseOr = 15 | BitwiseMask,
3248 LogicalAnd = 16 | LogicalMask,
3249 LogicalOr = 17 | LogicalMask,
3254 ValuesOnlyMask = ArithmeticMask - 1,
3255 ArithmeticMask = 1 << 5,
3257 ComparisonMask = 1 << 7,
3258 EqualityMask = 1 << 8,
3259 BitwiseMask = 1 << 9,
3260 LogicalMask = 1 << 10,
3261 AdditionMask = 1 << 11,
3262 SubtractionMask = 1 << 12,
3263 RelationalMask = 1 << 13,
3265 DecomposedMask = 1 << 19,
3266 NullableMask = 1 << 20
3270 public enum State : byte
3274 UserOperatorsExcluded = 1 << 2
3277 readonly Operator oper;
3278 Expression left, right;
3280 ConvCast.Mode enum_conversion;
3282 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3283 : this (oper, left, right, State.Compound)
3287 public Binary (Operator oper, Expression left, Expression right, State state)
3288 : this (oper, left, right)
3293 public Binary (Operator oper, Expression left, Expression right)
3294 : this (oper, left, right, left.Location)
3298 public Binary (Operator oper, Expression left, Expression right, Location loc)
3308 public bool IsCompound {
3310 return (state & State.Compound) != 0;
3314 public Operator Oper {
3320 public Expression Left {
3326 public Expression Right {
3332 public override Location StartLocation {
3334 return left.StartLocation;
3341 /// Returns a stringified representation of the Operator
3343 string OperName (Operator oper)
3347 case Operator.Multiply:
3350 case Operator.Division:
3353 case Operator.Modulus:
3356 case Operator.Addition:
3359 case Operator.Subtraction:
3362 case Operator.LeftShift:
3365 case Operator.RightShift:
3368 case Operator.LessThan:
3371 case Operator.GreaterThan:
3374 case Operator.LessThanOrEqual:
3377 case Operator.GreaterThanOrEqual:
3380 case Operator.Equality:
3383 case Operator.Inequality:
3386 case Operator.BitwiseAnd:
3389 case Operator.BitwiseOr:
3392 case Operator.ExclusiveOr:
3395 case Operator.LogicalOr:
3398 case Operator.LogicalAnd:
3402 s = oper.ToString ();
3412 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3414 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3417 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3419 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3423 l = left.Type.GetSignatureForError ();
3424 r = right.Type.GetSignatureForError ();
3426 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3430 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3432 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3435 public override void FlowAnalysis (FlowAnalysisContext fc)
3438 // Optimized version when on-true/on-false data are not needed
3440 if ((oper & Operator.LogicalMask) == 0) {
3441 left.FlowAnalysis (fc);
3442 right.FlowAnalysis (fc);
3446 left.FlowAnalysisConditional (fc);
3447 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3448 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3450 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3451 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3452 right.FlowAnalysisConditional (fc);
3454 if (oper == Operator.LogicalOr)
3455 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3457 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3460 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3462 if ((oper & Operator.LogicalMask) == 0) {
3463 base.FlowAnalysisConditional (fc);
3467 left.FlowAnalysisConditional (fc);
3468 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3469 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3471 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3472 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3473 right.FlowAnalysisConditional (fc);
3475 var lc = left as Constant;
3476 if (oper == Operator.LogicalOr) {
3477 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3478 if (lc != null && lc.IsDefaultValue)
3479 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3481 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3483 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3484 if (lc != null && !lc.IsDefaultValue)
3485 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3487 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3492 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3494 string GetOperatorExpressionTypeName ()
3497 case Operator.Addition:
3498 return IsCompound ? "AddAssign" : "Add";
3499 case Operator.BitwiseAnd:
3500 return IsCompound ? "AndAssign" : "And";
3501 case Operator.BitwiseOr:
3502 return IsCompound ? "OrAssign" : "Or";
3503 case Operator.Division:
3504 return IsCompound ? "DivideAssign" : "Divide";
3505 case Operator.ExclusiveOr:
3506 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3507 case Operator.Equality:
3509 case Operator.GreaterThan:
3510 return "GreaterThan";
3511 case Operator.GreaterThanOrEqual:
3512 return "GreaterThanOrEqual";
3513 case Operator.Inequality:
3515 case Operator.LeftShift:
3516 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3517 case Operator.LessThan:
3519 case Operator.LessThanOrEqual:
3520 return "LessThanOrEqual";
3521 case Operator.LogicalAnd:
3523 case Operator.LogicalOr:
3525 case Operator.Modulus:
3526 return IsCompound ? "ModuloAssign" : "Modulo";
3527 case Operator.Multiply:
3528 return IsCompound ? "MultiplyAssign" : "Multiply";
3529 case Operator.RightShift:
3530 return IsCompound ? "RightShiftAssign" : "RightShift";
3531 case Operator.Subtraction:
3532 return IsCompound ? "SubtractAssign" : "Subtract";
3534 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3538 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3541 case Operator.Addition:
3542 return CSharp.Operator.OpType.Addition;
3543 case Operator.BitwiseAnd:
3544 case Operator.LogicalAnd:
3545 return CSharp.Operator.OpType.BitwiseAnd;
3546 case Operator.BitwiseOr:
3547 case Operator.LogicalOr:
3548 return CSharp.Operator.OpType.BitwiseOr;
3549 case Operator.Division:
3550 return CSharp.Operator.OpType.Division;
3551 case Operator.Equality:
3552 return CSharp.Operator.OpType.Equality;
3553 case Operator.ExclusiveOr:
3554 return CSharp.Operator.OpType.ExclusiveOr;
3555 case Operator.GreaterThan:
3556 return CSharp.Operator.OpType.GreaterThan;
3557 case Operator.GreaterThanOrEqual:
3558 return CSharp.Operator.OpType.GreaterThanOrEqual;
3559 case Operator.Inequality:
3560 return CSharp.Operator.OpType.Inequality;
3561 case Operator.LeftShift:
3562 return CSharp.Operator.OpType.LeftShift;
3563 case Operator.LessThan:
3564 return CSharp.Operator.OpType.LessThan;
3565 case Operator.LessThanOrEqual:
3566 return CSharp.Operator.OpType.LessThanOrEqual;
3567 case Operator.Modulus:
3568 return CSharp.Operator.OpType.Modulus;
3569 case Operator.Multiply:
3570 return CSharp.Operator.OpType.Multiply;
3571 case Operator.RightShift:
3572 return CSharp.Operator.OpType.RightShift;
3573 case Operator.Subtraction:
3574 return CSharp.Operator.OpType.Subtraction;
3576 throw new InternalErrorException (op.ToString ());
3580 public override bool ContainsEmitWithAwait ()
3582 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3585 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3590 case Operator.Multiply:
3591 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3592 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3593 opcode = OpCodes.Mul_Ovf;
3594 else if (!IsFloat (l))
3595 opcode = OpCodes.Mul_Ovf_Un;
3597 opcode = OpCodes.Mul;
3599 opcode = OpCodes.Mul;
3603 case Operator.Division:
3605 opcode = OpCodes.Div_Un;
3607 opcode = OpCodes.Div;
3610 case Operator.Modulus:
3612 opcode = OpCodes.Rem_Un;
3614 opcode = OpCodes.Rem;
3617 case Operator.Addition:
3618 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3619 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3620 opcode = OpCodes.Add_Ovf;
3621 else if (!IsFloat (l))
3622 opcode = OpCodes.Add_Ovf_Un;
3624 opcode = OpCodes.Add;
3626 opcode = OpCodes.Add;
3629 case Operator.Subtraction:
3630 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3631 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3632 opcode = OpCodes.Sub_Ovf;
3633 else if (!IsFloat (l))
3634 opcode = OpCodes.Sub_Ovf_Un;
3636 opcode = OpCodes.Sub;
3638 opcode = OpCodes.Sub;
3641 case Operator.RightShift:
3642 if (!(right is IntConstant)) {
3643 ec.EmitInt (GetShiftMask (l));
3644 ec.Emit (OpCodes.And);
3648 opcode = OpCodes.Shr_Un;
3650 opcode = OpCodes.Shr;
3653 case Operator.LeftShift:
3654 if (!(right is IntConstant)) {
3655 ec.EmitInt (GetShiftMask (l));
3656 ec.Emit (OpCodes.And);
3659 opcode = OpCodes.Shl;
3662 case Operator.Equality:
3663 opcode = OpCodes.Ceq;
3666 case Operator.Inequality:
3667 ec.Emit (OpCodes.Ceq);
3670 opcode = OpCodes.Ceq;
3673 case Operator.LessThan:
3675 opcode = OpCodes.Clt_Un;
3677 opcode = OpCodes.Clt;
3680 case Operator.GreaterThan:
3682 opcode = OpCodes.Cgt_Un;
3684 opcode = OpCodes.Cgt;
3687 case Operator.LessThanOrEqual:
3688 if (IsUnsigned (l) || IsFloat (l))
3689 ec.Emit (OpCodes.Cgt_Un);
3691 ec.Emit (OpCodes.Cgt);
3694 opcode = OpCodes.Ceq;
3697 case Operator.GreaterThanOrEqual:
3698 if (IsUnsigned (l) || IsFloat (l))
3699 ec.Emit (OpCodes.Clt_Un);
3701 ec.Emit (OpCodes.Clt);
3705 opcode = OpCodes.Ceq;
3708 case Operator.BitwiseOr:
3709 opcode = OpCodes.Or;
3712 case Operator.BitwiseAnd:
3713 opcode = OpCodes.And;
3716 case Operator.ExclusiveOr:
3717 opcode = OpCodes.Xor;
3721 throw new InternalErrorException (oper.ToString ());
3727 static int GetShiftMask (TypeSpec type)
3729 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3732 static bool IsUnsigned (TypeSpec t)
3734 switch (t.BuiltinType) {
3735 case BuiltinTypeSpec.Type.Char:
3736 case BuiltinTypeSpec.Type.UInt:
3737 case BuiltinTypeSpec.Type.ULong:
3738 case BuiltinTypeSpec.Type.UShort:
3739 case BuiltinTypeSpec.Type.Byte:
3746 static bool IsFloat (TypeSpec t)
3748 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3751 public Expression ResolveOperator (ResolveContext rc)
3753 eclass = ExprClass.Value;
3755 TypeSpec l = left.Type;
3756 TypeSpec r = right.Type;
3758 bool primitives_only = false;
3761 // Handles predefined primitive types
3763 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3764 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3765 if ((oper & Operator.ShiftMask) == 0) {
3766 if (!DoBinaryOperatorPromotion (rc))
3769 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3773 if (l.IsPointer || r.IsPointer)
3774 return ResolveOperatorPointer (rc, l, r);
3777 if ((state & State.UserOperatorsExcluded) == 0) {
3778 expr = ResolveUserOperator (rc, left, right);
3783 bool lenum = l.IsEnum;
3784 bool renum = r.IsEnum;
3785 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3789 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3790 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3795 if ((oper & Operator.BitwiseMask) != 0) {
3796 expr = EmptyCast.Create (expr, type);
3797 enum_conversion = GetEnumResultCast (type);
3799 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3800 expr = OptimizeAndOperation (expr);
3804 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3805 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3808 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3809 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3813 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3816 // We cannot break here there is also Enum + String possible match
3817 // which is not ambiguous with predefined enum operators
3820 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3821 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3825 } else if (l.IsDelegate || r.IsDelegate) {
3829 expr = ResolveOperatorDelegate (rc, l, r);
3831 // TODO: Can this be ambiguous
3839 // Equality operators are more complicated
3841 if ((oper & Operator.EqualityMask) != 0) {
3842 return ResolveEquality (rc, l, r, primitives_only);
3845 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3849 if (primitives_only)
3853 // Lifted operators have lower priority
3855 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3858 static bool IsEnumOrNullableEnum (TypeSpec type)
3860 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3864 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3865 // if 'left' is not an enumeration constant, create one from the type of 'right'
3866 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3869 case Operator.BitwiseOr:
3870 case Operator.BitwiseAnd:
3871 case Operator.ExclusiveOr:
3872 case Operator.Equality:
3873 case Operator.Inequality:
3874 case Operator.LessThan:
3875 case Operator.LessThanOrEqual:
3876 case Operator.GreaterThan:
3877 case Operator.GreaterThanOrEqual:
3878 if (left.Type.IsEnum)
3881 if (left.IsZeroInteger)
3882 return left.Reduce (ec, right.Type);
3886 case Operator.Addition:
3887 case Operator.Subtraction:
3890 case Operator.Multiply:
3891 case Operator.Division:
3892 case Operator.Modulus:
3893 case Operator.LeftShift:
3894 case Operator.RightShift:
3895 if (right.Type.IsEnum || left.Type.IsEnum)
3904 // The `|' operator used on types which were extended is dangerous
3906 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3908 OpcodeCast lcast = left as OpcodeCast;
3909 if (lcast != null) {
3910 if (IsUnsigned (lcast.UnderlyingType))
3914 OpcodeCast rcast = right as OpcodeCast;
3915 if (rcast != null) {
3916 if (IsUnsigned (rcast.UnderlyingType))
3920 if (lcast == null && rcast == null)
3923 // FIXME: consider constants
3925 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3926 ec.Report.Warning (675, 3, loc,
3927 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3928 ltype.GetSignatureForError ());
3931 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3933 return new PredefinedOperator[] {
3935 // Pointer arithmetic:
3937 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3938 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3939 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3940 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3942 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3943 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3944 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3945 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3948 // T* operator + (int y, T* x);
3949 // T* operator + (uint y, T *x);
3950 // T* operator + (long y, T *x);
3951 // T* operator + (ulong y, T *x);
3953 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3954 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3955 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3956 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3959 // long operator - (T* x, T *y)
3961 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3965 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3967 TypeSpec bool_type = types.Bool;
3970 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3971 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3972 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3973 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3974 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3975 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3976 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3978 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3979 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3980 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3981 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3982 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3983 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3984 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3986 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3987 // Remaining string operators are in lifted tables
3989 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3991 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3992 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3993 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3997 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3999 var types = module.Compiler.BuiltinTypes;
4002 // Not strictly lifted but need to be in second group otherwise expressions like
4003 // int + null would resolve to +(object, string) instead of +(int?, int?)
4005 var string_operators = new [] {
4006 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
4007 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
4010 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4011 if (nullable == null)
4012 return string_operators;
4014 var bool_type = types.Bool;
4016 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
4017 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4018 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4019 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4020 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4021 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4022 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4023 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4026 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4027 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4028 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4029 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4030 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4031 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4032 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4034 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4035 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4036 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4037 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4038 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4039 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4040 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4042 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4044 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4045 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4046 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4048 string_operators [0],
4049 string_operators [1]
4053 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4055 TypeSpec bool_type = types.Bool;
4058 new PredefinedEqualityOperator (types.String, bool_type),
4059 new PredefinedEqualityOperator (types.Delegate, bool_type),
4060 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4061 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4062 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4063 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4064 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4065 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4066 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4067 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4071 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4073 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4075 if (nullable == null)
4076 return new PredefinedOperator [0];
4078 var types = module.Compiler.BuiltinTypes;
4079 var bool_type = types.Bool;
4080 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4081 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4082 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4083 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4084 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4085 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4086 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4087 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4090 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4091 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4092 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4093 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4094 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4095 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4096 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4097 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4102 // 7.2.6.2 Binary numeric promotions
4104 bool DoBinaryOperatorPromotion (ResolveContext rc)
4106 TypeSpec ltype = left.Type;
4107 if (ltype.IsNullableType) {
4108 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4112 // This is numeric promotion code only
4114 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4117 TypeSpec rtype = right.Type;
4118 if (rtype.IsNullableType) {
4119 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4122 var lb = ltype.BuiltinType;
4123 var rb = rtype.BuiltinType;
4127 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4128 type = rc.BuiltinTypes.Decimal;
4129 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4130 type = rc.BuiltinTypes.Double;
4131 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4132 type = rc.BuiltinTypes.Float;
4133 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4134 type = rc.BuiltinTypes.ULong;
4136 if (IsSignedType (lb)) {
4137 expr = ConvertSignedConstant (left, type);
4141 } else if (IsSignedType (rb)) {
4142 expr = ConvertSignedConstant (right, type);
4148 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4149 type = rc.BuiltinTypes.Long;
4150 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4151 type = rc.BuiltinTypes.UInt;
4153 if (IsSignedType (lb)) {
4154 expr = ConvertSignedConstant (left, type);
4156 type = rc.BuiltinTypes.Long;
4157 } else if (IsSignedType (rb)) {
4158 expr = ConvertSignedConstant (right, type);
4160 type = rc.BuiltinTypes.Long;
4163 type = rc.BuiltinTypes.Int;
4166 if (ltype != type) {
4167 expr = PromoteExpression (rc, left, type);
4174 if (rtype != type) {
4175 expr = PromoteExpression (rc, right, type);
4185 static bool IsSignedType (BuiltinTypeSpec.Type type)
4188 case BuiltinTypeSpec.Type.Int:
4189 case BuiltinTypeSpec.Type.Short:
4190 case BuiltinTypeSpec.Type.SByte:
4191 case BuiltinTypeSpec.Type.Long:
4198 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4200 var c = expr as Constant;
4204 return c.ConvertImplicitly (type);
4207 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4209 if (expr.Type.IsNullableType) {
4210 return Convert.ImplicitConversionStandard (rc, expr,
4211 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4214 var c = expr as Constant;
4216 return c.ConvertImplicitly (type);
4218 return Convert.ImplicitNumericConversion (expr, type);
4221 protected override Expression DoResolve (ResolveContext ec)
4226 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4227 left = ((ParenthesizedExpression) left).Expr;
4228 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4232 if (left.eclass == ExprClass.Type) {
4233 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4237 left = left.Resolve (ec);
4242 right = right.Resolve (ec);
4246 Constant lc = left as Constant;
4247 Constant rc = right as Constant;
4249 // The conversion rules are ignored in enum context but why
4250 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4251 lc = EnumLiftUp (ec, lc, rc);
4253 rc = EnumLiftUp (ec, rc, lc);
4256 if (rc != null && lc != null) {
4257 int prev_e = ec.Report.Errors;
4258 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4259 if (e != null || ec.Report.Errors != prev_e)
4263 // Comparison warnings
4264 if ((oper & Operator.ComparisonMask) != 0) {
4265 if (left.Equals (right)) {
4266 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4268 CheckOutOfRangeComparison (ec, lc, right.Type);
4269 CheckOutOfRangeComparison (ec, rc, left.Type);
4272 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4273 return DoResolveDynamic (ec);
4275 return DoResolveCore (ec, left, right);
4278 Expression DoResolveDynamic (ResolveContext rc)
4281 var rt = right.Type;
4282 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4283 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4284 Error_OperatorCannotBeApplied (rc, left, right);
4291 // Special handling for logical boolean operators which require rhs not to be
4292 // evaluated based on lhs value
4294 if ((oper & Operator.LogicalMask) != 0) {
4295 Expression cond_left, cond_right, expr;
4297 args = new Arguments (2);
4299 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4300 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4302 var cond_args = new Arguments (1);
4303 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4306 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4307 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4309 left = temp.CreateReferenceExpression (rc, loc);
4310 if (oper == Operator.LogicalAnd) {
4311 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4314 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4318 args.Add (new Argument (left));
4319 args.Add (new Argument (right));
4320 cond_right = new DynamicExpressionStatement (this, args, loc);
4322 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4324 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4325 rc.Report.Error (7083, left.Location,
4326 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4327 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4331 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4332 args.Add (new Argument (right));
4333 right = new DynamicExpressionStatement (this, args, loc);
4336 // bool && dynamic => (temp = left) ? temp && right : temp;
4337 // bool || dynamic => (temp = left) ? temp : temp || right;
4339 if (oper == Operator.LogicalAnd) {
4341 cond_right = temp.CreateReferenceExpression (rc, loc);
4343 cond_left = temp.CreateReferenceExpression (rc, loc);
4347 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4350 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4353 args = new Arguments (2);
4354 args.Add (new Argument (left));
4355 args.Add (new Argument (right));
4356 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4359 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4361 Expression expr = ResolveOperator (ec);
4363 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4365 if (left == null || right == null)
4366 throw new InternalErrorException ("Invalid conversion");
4368 if (oper == Operator.BitwiseOr)
4369 CheckBitwiseOrOnSignExtended (ec);
4374 public override SLE.Expression MakeExpression (BuilderContext ctx)
4376 return MakeExpression (ctx, left, right);
4379 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4381 var le = left.MakeExpression (ctx);
4382 var re = right.MakeExpression (ctx);
4383 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4386 case Operator.Addition:
4387 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4388 case Operator.BitwiseAnd:
4389 return SLE.Expression.And (le, re);
4390 case Operator.BitwiseOr:
4391 return SLE.Expression.Or (le, re);
4392 case Operator.Division:
4393 return SLE.Expression.Divide (le, re);
4394 case Operator.Equality:
4395 return SLE.Expression.Equal (le, re);
4396 case Operator.ExclusiveOr:
4397 return SLE.Expression.ExclusiveOr (le, re);
4398 case Operator.GreaterThan:
4399 return SLE.Expression.GreaterThan (le, re);
4400 case Operator.GreaterThanOrEqual:
4401 return SLE.Expression.GreaterThanOrEqual (le, re);
4402 case Operator.Inequality:
4403 return SLE.Expression.NotEqual (le, re);
4404 case Operator.LeftShift:
4405 return SLE.Expression.LeftShift (le, re);
4406 case Operator.LessThan:
4407 return SLE.Expression.LessThan (le, re);
4408 case Operator.LessThanOrEqual:
4409 return SLE.Expression.LessThanOrEqual (le, re);
4410 case Operator.LogicalAnd:
4411 return SLE.Expression.AndAlso (le, re);
4412 case Operator.LogicalOr:
4413 return SLE.Expression.OrElse (le, re);
4414 case Operator.Modulus:
4415 return SLE.Expression.Modulo (le, re);
4416 case Operator.Multiply:
4417 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4418 case Operator.RightShift:
4419 return SLE.Expression.RightShift (le, re);
4420 case Operator.Subtraction:
4421 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4423 throw new NotImplementedException (oper.ToString ());
4428 // D operator + (D x, D y)
4429 // D operator - (D x, D y)
4431 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4433 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4435 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4436 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4441 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4442 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4452 MethodSpec method = null;
4453 Arguments args = new Arguments (2);
4454 args.Add (new Argument (left));
4455 args.Add (new Argument (right));
4457 if (oper == Operator.Addition) {
4458 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4459 } else if (oper == Operator.Subtraction) {
4460 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4464 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4466 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4467 return new ClassCast (expr, l);
4471 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4473 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4476 // bool operator == (E x, E y);
4477 // bool operator != (E x, E y);
4478 // bool operator < (E x, E y);
4479 // bool operator > (E x, E y);
4480 // bool operator <= (E x, E y);
4481 // bool operator >= (E x, E y);
4483 // E operator & (E x, E y);
4484 // E operator | (E x, E y);
4485 // E operator ^ (E x, E y);
4488 if ((oper & Operator.ComparisonMask) != 0) {
4489 type = rc.BuiltinTypes.Bool;
4495 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4501 if (ltype == rtype) {
4505 var lifted = new Nullable.LiftedBinaryOperator (this);
4507 lifted.Right = right;
4508 return lifted.Resolve (rc);
4511 if (renum && !ltype.IsNullableType) {
4512 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4517 } else if (lenum && !rtype.IsNullableType) {
4518 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4526 // Now try lifted version of predefined operator
4528 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4529 if (nullable_type != null) {
4530 if (renum && !ltype.IsNullableType) {
4531 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4533 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4536 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4539 if ((oper & Operator.BitwiseMask) != 0)
4543 if ((oper & Operator.BitwiseMask) != 0)
4544 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4546 return CreateLiftedValueTypeResult (rc, rtype);
4550 var lifted = new Nullable.LiftedBinaryOperator (this);
4552 lifted.Right = right;
4553 return lifted.Resolve (rc);
4555 } else if (lenum && !rtype.IsNullableType) {
4556 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4558 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4561 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4564 if ((oper & Operator.BitwiseMask) != 0)
4568 if ((oper & Operator.BitwiseMask) != 0)
4569 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4571 return CreateLiftedValueTypeResult (rc, ltype);
4575 var lifted = new Nullable.LiftedBinaryOperator (this);
4577 lifted.Right = expr;
4578 return lifted.Resolve (rc);
4580 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4581 Nullable.Unwrap unwrap = null;
4582 if (left.IsNull || right.IsNull) {
4583 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4584 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4586 if ((oper & Operator.RelationalMask) != 0)
4587 return CreateLiftedValueTypeResult (rc, rtype);
4589 if ((oper & Operator.BitwiseMask) != 0)
4590 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4593 return CreateLiftedValueTypeResult (rc, left.Type);
4595 // Equality operators are valid between E? and null
4597 unwrap = new Nullable.Unwrap (right);
4599 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4603 if ((oper & Operator.BitwiseMask) != 0)
4608 var lifted = new Nullable.LiftedBinaryOperator (this);
4610 lifted.Right = right;
4611 lifted.UnwrapRight = unwrap;
4612 return lifted.Resolve (rc);
4614 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4615 Nullable.Unwrap unwrap = null;
4616 if (right.IsNull || left.IsNull) {
4617 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4618 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4620 if ((oper & Operator.RelationalMask) != 0)
4621 return CreateLiftedValueTypeResult (rc, ltype);
4623 if ((oper & Operator.BitwiseMask) != 0)
4624 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4627 return CreateLiftedValueTypeResult (rc, right.Type);
4629 // Equality operators are valid between E? and null
4631 unwrap = new Nullable.Unwrap (left);
4633 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4637 if ((oper & Operator.BitwiseMask) != 0)
4642 var lifted = new Nullable.LiftedBinaryOperator (this);
4644 lifted.UnwrapLeft = unwrap;
4645 lifted.Right = expr;
4646 return lifted.Resolve (rc);
4654 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4656 TypeSpec underlying_type;
4657 if (expr.Type.IsNullableType) {
4658 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4660 underlying_type = EnumSpec.GetUnderlyingType (nt);
4662 underlying_type = nt;
4663 } else if (expr.Type.IsEnum) {
4664 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4666 underlying_type = expr.Type;
4669 switch (underlying_type.BuiltinType) {
4670 case BuiltinTypeSpec.Type.SByte:
4671 case BuiltinTypeSpec.Type.Byte:
4672 case BuiltinTypeSpec.Type.Short:
4673 case BuiltinTypeSpec.Type.UShort:
4674 underlying_type = rc.BuiltinTypes.Int;
4678 if (expr.Type.IsNullableType || liftType)
4679 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4681 if (expr.Type == underlying_type)
4684 return EmptyCast.Create (expr, underlying_type);
4687 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4690 // U operator - (E e, E f)
4691 // E operator - (E e, U x) // Internal decomposition operator
4692 // E operator - (U x, E e) // Internal decomposition operator
4694 // E operator + (E e, U x)
4695 // E operator + (U x, E e)
4704 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4710 if (!enum_type.IsNullableType) {
4711 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4713 if (oper == Operator.Subtraction)
4714 expr = ConvertEnumSubtractionResult (rc, expr);
4716 expr = ConvertEnumAdditionalResult (expr, enum_type);
4718 enum_conversion = GetEnumResultCast (expr.Type);
4723 var nullable = rc.Module.PredefinedTypes.Nullable;
4726 // Don't try nullable version when nullable type is undefined
4728 if (!nullable.IsDefined)
4731 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4734 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4736 if (oper == Operator.Subtraction)
4737 expr = ConvertEnumSubtractionResult (rc, expr);
4739 expr = ConvertEnumAdditionalResult (expr, enum_type);
4741 enum_conversion = GetEnumResultCast (expr.Type);
4747 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4749 return EmptyCast.Create (expr, enumType);
4752 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4755 // Enumeration subtraction has different result type based on
4758 TypeSpec result_type;
4759 if (left.Type == right.Type) {
4760 var c = right as EnumConstant;
4761 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4763 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4764 // E which is not what expressions E - 1 or 0 - E return
4766 result_type = left.Type;
4768 result_type = left.Type.IsNullableType ?
4769 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4770 EnumSpec.GetUnderlyingType (left.Type);
4773 if (IsEnumOrNullableEnum (left.Type)) {
4774 result_type = left.Type;
4776 result_type = right.Type;
4779 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4780 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4783 return EmptyCast.Create (expr, result_type);
4786 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4788 if (type.IsNullableType)
4789 type = Nullable.NullableInfo.GetUnderlyingType (type);
4792 type = EnumSpec.GetUnderlyingType (type);
4794 switch (type.BuiltinType) {
4795 case BuiltinTypeSpec.Type.SByte:
4796 return ConvCast.Mode.I4_I1;
4797 case BuiltinTypeSpec.Type.Byte:
4798 return ConvCast.Mode.I4_U1;
4799 case BuiltinTypeSpec.Type.Short:
4800 return ConvCast.Mode.I4_I2;
4801 case BuiltinTypeSpec.Type.UShort:
4802 return ConvCast.Mode.I4_U2;
4809 // Equality operators rules
4811 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4814 type = ec.BuiltinTypes.Bool;
4815 bool no_arg_conv = false;
4817 if (!primitives_only) {
4820 // a, Both operands are reference-type values or the value null
4821 // b, One operand is a value of type T where T is a type-parameter and
4822 // the other operand is the value null. Furthermore T does not have the
4823 // value type constraint
4825 // LAMESPEC: Very confusing details in the specification, basically any
4826 // reference like type-parameter is allowed
4828 var tparam_l = l as TypeParameterSpec;
4829 var tparam_r = r as TypeParameterSpec;
4830 if (tparam_l != null) {
4831 if (right is NullLiteral) {
4832 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4835 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4839 if (!tparam_l.IsReferenceType)
4842 l = tparam_l.GetEffectiveBase ();
4843 left = new BoxedCast (left, l);
4844 } else if (left is NullLiteral && tparam_r == null) {
4845 if (TypeSpec.IsReferenceType (r))
4848 if (r.Kind == MemberKind.InternalCompilerType)
4852 if (tparam_r != null) {
4853 if (left is NullLiteral) {
4854 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4857 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4861 if (!tparam_r.IsReferenceType)
4864 r = tparam_r.GetEffectiveBase ();
4865 right = new BoxedCast (right, r);
4866 } else if (right is NullLiteral) {
4867 if (TypeSpec.IsReferenceType (l))
4870 if (l.Kind == MemberKind.InternalCompilerType)
4875 // LAMESPEC: method groups can be compared when they convert to other side delegate
4878 if (right.eclass == ExprClass.MethodGroup) {
4879 result = Convert.ImplicitConversion (ec, right, l, loc);
4885 } else if (r.IsDelegate && l != r) {
4888 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4889 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4896 no_arg_conv = l == r && !l.IsStruct;
4901 // bool operator != (string a, string b)
4902 // bool operator == (string a, string b)
4904 // bool operator != (Delegate a, Delegate b)
4905 // bool operator == (Delegate a, Delegate b)
4907 // bool operator != (bool a, bool b)
4908 // bool operator == (bool a, bool b)
4910 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4911 // they implement an implicit conversion to any of types above. This does
4912 // not apply when both operands are of same reference type
4914 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4915 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4920 // Now try lifted version of predefined operators
4922 if (no_arg_conv && !l.IsNullableType) {
4924 // Optimizes cases which won't match
4927 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4933 // The == and != operators permit one operand to be a value of a nullable
4934 // type and the other to be the null literal, even if no predefined or user-defined
4935 // operator (in unlifted or lifted form) exists for the operation.
4937 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4938 var lifted = new Nullable.LiftedBinaryOperator (this);
4940 lifted.Right = right;
4941 return lifted.Resolve (ec);
4946 // bool operator != (object a, object b)
4947 // bool operator == (object a, object b)
4949 // An explicit reference conversion exists from the
4950 // type of either operand to the type of the other operand.
4953 // Optimize common path
4955 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4958 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4959 !Convert.ExplicitReferenceConversionExists (r, l))
4962 // Reject allowed explicit conversions like int->object
4963 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4966 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4967 ec.Report.Warning (253, 2, loc,
4968 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4969 l.GetSignatureForError ());
4971 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4972 ec.Report.Warning (252, 2, loc,
4973 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4974 r.GetSignatureForError ());
4980 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4983 // bool operator == (void* x, void* y);
4984 // bool operator != (void* x, void* y);
4985 // bool operator < (void* x, void* y);
4986 // bool operator > (void* x, void* y);
4987 // bool operator <= (void* x, void* y);
4988 // bool operator >= (void* x, void* y);
4990 if ((oper & Operator.ComparisonMask) != 0) {
4993 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
5000 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
5006 type = ec.BuiltinTypes.Bool;
5010 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
5014 // Build-in operators method overloading
5016 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
5018 PredefinedOperator best_operator = null;
5019 TypeSpec l = left.Type;
5020 TypeSpec r = right.Type;
5021 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5023 foreach (PredefinedOperator po in operators) {
5024 if ((po.OperatorsMask & oper_mask) == 0)
5027 if (primitives_only) {
5028 if (!po.IsPrimitiveApplicable (l, r))
5031 if (!po.IsApplicable (ec, left, right))
5035 if (best_operator == null) {
5037 if (primitives_only)
5043 best_operator = po.ResolveBetterOperator (ec, best_operator);
5045 if (best_operator == null) {
5046 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5047 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5054 if (best_operator == null)
5057 return best_operator.ConvertResult (ec, this);
5061 // Optimize & constant expressions with 0 value
5063 Expression OptimizeAndOperation (Expression expr)
5065 Constant rc = right as Constant;
5066 Constant lc = left as Constant;
5067 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5069 // The result is a constant with side-effect
5071 Constant side_effect = rc == null ?
5072 new SideEffectConstant (lc, right, loc) :
5073 new SideEffectConstant (rc, left, loc);
5075 return ReducedExpression.Create (side_effect, expr);
5082 // Value types can be compared with the null literal because of the lifting
5083 // language rules. However the result is always true or false.
5085 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5087 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5088 type = rc.BuiltinTypes.Bool;
5092 // FIXME: Handle side effect constants
5093 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5095 if ((Oper & Operator.EqualityMask) != 0) {
5096 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5097 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5099 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5100 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5107 // Performs user-operator overloading
5109 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5111 Expression oper_expr;
5113 var op = ConvertBinaryToUserOperator (oper);
5115 if (l.IsNullableType)
5116 l = Nullable.NullableInfo.GetUnderlyingType (l);
5118 if (r.IsNullableType)
5119 r = Nullable.NullableInfo.GetUnderlyingType (r);
5121 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5122 IList<MemberSpec> right_operators = null;
5125 right_operators = MemberCache.GetUserOperator (r, op, false);
5126 if (right_operators == null && left_operators == null)
5128 } else if (left_operators == null) {
5132 Arguments args = new Arguments (2);
5133 Argument larg = new Argument (left);
5135 Argument rarg = new Argument (right);
5139 // User-defined operator implementations always take precedence
5140 // over predefined operator implementations
5142 if (left_operators != null && right_operators != null) {
5143 left_operators = CombineUserOperators (left_operators, right_operators);
5144 } else if (right_operators != null) {
5145 left_operators = right_operators;
5148 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5149 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5151 var res = new OverloadResolver (left_operators, restr, loc);
5153 var oper_method = res.ResolveOperator (rc, ref args);
5154 if (oper_method == null) {
5156 // Logical && and || cannot be lifted
5158 if ((oper & Operator.LogicalMask) != 0)
5162 // Apply lifted user operators only for liftable types. Implicit conversion
5163 // to nullable types is not allowed
5165 if (!IsLiftedOperatorApplicable ())
5168 // TODO: Cache the result in module container
5169 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5170 if (lifted_methods == null)
5173 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5175 oper_method = res.ResolveOperator (rc, ref args);
5176 if (oper_method == null)
5179 MethodSpec best_original = null;
5180 foreach (MethodSpec ms in left_operators) {
5181 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5187 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5189 // Expression trees use lifted notation in this case
5191 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5192 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5195 var ptypes = best_original.Parameters.Types;
5197 if (left.IsNull || right.IsNull) {
5199 // The lifted operator produces a null value if one or both operands are null
5201 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5202 type = oper_method.ReturnType;
5203 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5207 // The lifted operator produces the value false if one or both operands are null for
5208 // relational operators.
5210 if ((oper & Operator.RelationalMask) != 0) {
5212 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5213 // because return type is actually bool
5215 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5218 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5219 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5223 type = oper_method.ReturnType;
5224 var lifted = new Nullable.LiftedBinaryOperator (this);
5225 lifted.UserOperator = best_original;
5227 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5228 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5231 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5232 lifted.UnwrapRight = new Nullable.Unwrap (right);
5235 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5236 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5238 return lifted.Resolve (rc);
5241 if ((oper & Operator.LogicalMask) != 0) {
5242 // TODO: CreateExpressionTree is allocated every time
5243 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5244 oper == Operator.LogicalAnd, loc).Resolve (rc);
5246 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5249 this.left = larg.Expr;
5250 this.right = rarg.Expr;
5255 bool IsLiftedOperatorApplicable ()
5257 if (left.Type.IsNullableType) {
5258 if ((oper & Operator.EqualityMask) != 0)
5259 return !right.IsNull;
5264 if (right.Type.IsNullableType) {
5265 if ((oper & Operator.EqualityMask) != 0)
5266 return !left.IsNull;
5271 if (TypeSpec.IsValueType (left.Type))
5272 return right.IsNull;
5274 if (TypeSpec.IsValueType (right.Type))
5280 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5282 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5283 if (nullable_type == null)
5287 // Lifted operators permit predefined and user-defined operators that operate
5288 // on non-nullable value types to also be used with nullable forms of those types.
5289 // Lifted operators are constructed from predefined and user-defined operators
5290 // that meet certain requirements
5292 List<MemberSpec> lifted = null;
5293 foreach (MethodSpec oper in operators) {
5295 if ((Oper & Operator.ComparisonMask) != 0) {
5297 // Result type must be of type bool for lifted comparison operators
5299 rt = oper.ReturnType;
5300 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5303 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5309 var ptypes = oper.Parameters.Types;
5310 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5314 // LAMESPEC: I am not sure why but for equality operators to be lifted
5315 // both types have to match
5317 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5321 lifted = new List<MemberSpec> ();
5324 // The lifted form is constructed by adding a single ? modifier to each operand and
5325 // result type except for comparison operators where return type is bool
5328 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5330 var parameters = ParametersCompiled.CreateFullyResolved (
5331 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5332 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5334 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5335 rt, parameters, oper.Modifiers);
5337 lifted.Add (lifted_op);
5344 // Merge two sets of user operators into one, they are mostly distinguish
5345 // except when they share base type and it contains an operator
5347 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5349 var combined = new List<MemberSpec> (left.Count + right.Count);
5350 combined.AddRange (left);
5351 foreach (var r in right) {
5353 foreach (var l in left) {
5354 if (l.DeclaringType == r.DeclaringType) {
5367 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5369 if (c is IntegralConstant || c is CharConstant) {
5371 c.ConvertExplicitly (true, type);
5372 } catch (OverflowException) {
5373 ec.Report.Warning (652, 2, loc,
5374 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5375 type.GetSignatureForError ());
5381 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5382 /// context of a conditional bool expression. This function will return
5383 /// false if it is was possible to use EmitBranchable, or true if it was.
5385 /// The expression's code is generated, and we will generate a branch to `target'
5386 /// if the resulting expression value is equal to isTrue
5388 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5390 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5391 left = left.EmitToField (ec);
5393 if ((oper & Operator.LogicalMask) == 0) {
5394 right = right.EmitToField (ec);
5399 // This is more complicated than it looks, but its just to avoid
5400 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5401 // but on top of that we want for == and != to use a special path
5402 // if we are comparing against null
5404 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5405 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5408 // put the constant on the rhs, for simplicity
5410 if (left is Constant) {
5411 Expression swap = right;
5417 // brtrue/brfalse works with native int only
5419 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5420 left.EmitBranchable (ec, target, my_on_true);
5423 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5424 // right is a boolean, and it's not 'false' => it is 'true'
5425 left.EmitBranchable (ec, target, !my_on_true);
5429 } else if (oper == Operator.LogicalAnd) {
5432 Label tests_end = ec.DefineLabel ();
5434 left.EmitBranchable (ec, tests_end, false);
5435 right.EmitBranchable (ec, target, true);
5436 ec.MarkLabel (tests_end);
5439 // This optimizes code like this
5440 // if (true && i > 4)
5442 if (!(left is Constant))
5443 left.EmitBranchable (ec, target, false);
5445 if (!(right is Constant))
5446 right.EmitBranchable (ec, target, false);
5451 } else if (oper == Operator.LogicalOr){
5453 left.EmitBranchable (ec, target, true);
5454 right.EmitBranchable (ec, target, true);
5457 Label tests_end = ec.DefineLabel ();
5458 left.EmitBranchable (ec, tests_end, true);
5459 right.EmitBranchable (ec, target, false);
5460 ec.MarkLabel (tests_end);
5465 } else if ((oper & Operator.ComparisonMask) == 0) {
5466 base.EmitBranchable (ec, target, on_true);
5473 TypeSpec t = left.Type;
5474 bool is_float = IsFloat (t);
5475 bool is_unsigned = is_float || IsUnsigned (t);
5478 case Operator.Equality:
5480 ec.Emit (OpCodes.Beq, target);
5482 ec.Emit (OpCodes.Bne_Un, target);
5485 case Operator.Inequality:
5487 ec.Emit (OpCodes.Bne_Un, target);
5489 ec.Emit (OpCodes.Beq, target);
5492 case Operator.LessThan:
5494 if (is_unsigned && !is_float)
5495 ec.Emit (OpCodes.Blt_Un, target);
5497 ec.Emit (OpCodes.Blt, target);
5500 ec.Emit (OpCodes.Bge_Un, target);
5502 ec.Emit (OpCodes.Bge, target);
5505 case Operator.GreaterThan:
5507 if (is_unsigned && !is_float)
5508 ec.Emit (OpCodes.Bgt_Un, target);
5510 ec.Emit (OpCodes.Bgt, target);
5513 ec.Emit (OpCodes.Ble_Un, target);
5515 ec.Emit (OpCodes.Ble, target);
5518 case Operator.LessThanOrEqual:
5520 if (is_unsigned && !is_float)
5521 ec.Emit (OpCodes.Ble_Un, target);
5523 ec.Emit (OpCodes.Ble, target);
5526 ec.Emit (OpCodes.Bgt_Un, target);
5528 ec.Emit (OpCodes.Bgt, target);
5532 case Operator.GreaterThanOrEqual:
5534 if (is_unsigned && !is_float)
5535 ec.Emit (OpCodes.Bge_Un, target);
5537 ec.Emit (OpCodes.Bge, target);
5540 ec.Emit (OpCodes.Blt_Un, target);
5542 ec.Emit (OpCodes.Blt, target);
5545 throw new InternalErrorException (oper.ToString ());
5549 public override void Emit (EmitContext ec)
5551 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5552 left = left.EmitToField (ec);
5554 if ((oper & Operator.LogicalMask) == 0) {
5555 right = right.EmitToField (ec);
5560 // Handle short-circuit operators differently
5563 if ((oper & Operator.LogicalMask) != 0) {
5564 Label load_result = ec.DefineLabel ();
5565 Label end = ec.DefineLabel ();
5567 bool is_or = oper == Operator.LogicalOr;
5568 left.EmitBranchable (ec, load_result, is_or);
5570 ec.Emit (OpCodes.Br_S, end);
5572 ec.MarkLabel (load_result);
5573 ec.EmitInt (is_or ? 1 : 0);
5579 // Optimize zero-based operations which cannot be optimized at expression level
5581 if (oper == Operator.Subtraction) {
5582 var lc = left as IntegralConstant;
5583 if (lc != null && lc.IsDefaultValue) {
5585 ec.Emit (OpCodes.Neg);
5590 EmitOperator (ec, left, right);
5593 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5598 EmitOperatorOpcode (ec, oper, left.Type, right);
5601 // Emit result enumerable conversion this way because it's quite complicated get it
5602 // to resolved tree because expression tree cannot see it.
5604 if (enum_conversion != 0)
5605 ConvCast.Emit (ec, enum_conversion);
5608 public override void EmitSideEffect (EmitContext ec)
5610 if ((oper & Operator.LogicalMask) != 0 ||
5611 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5612 base.EmitSideEffect (ec);
5614 left.EmitSideEffect (ec);
5615 right.EmitSideEffect (ec);
5619 public override Expression EmitToField (EmitContext ec)
5621 if ((oper & Operator.LogicalMask) == 0) {
5622 var await_expr = left as Await;
5623 if (await_expr != null && right.IsSideEffectFree) {
5624 await_expr.Statement.EmitPrologue (ec);
5625 left = await_expr.Statement.GetResultExpression (ec);
5629 await_expr = right as Await;
5630 if (await_expr != null && left.IsSideEffectFree) {
5631 await_expr.Statement.EmitPrologue (ec);
5632 right = await_expr.Statement.GetResultExpression (ec);
5637 return base.EmitToField (ec);
5640 protected override void CloneTo (CloneContext clonectx, Expression t)
5642 Binary target = (Binary) t;
5644 target.left = left.Clone (clonectx);
5645 target.right = right.Clone (clonectx);
5648 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5650 Arguments binder_args = new Arguments (4);
5652 MemberAccess sle = new MemberAccess (new MemberAccess (
5653 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5655 CSharpBinderFlags flags = 0;
5656 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5657 flags = CSharpBinderFlags.CheckedContext;
5659 if ((oper & Operator.LogicalMask) != 0)
5660 flags |= CSharpBinderFlags.BinaryOperationLogical;
5662 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5663 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5664 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5665 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5667 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5670 public override Expression CreateExpressionTree (ResolveContext ec)
5672 return CreateExpressionTree (ec, null);
5675 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5678 bool lift_arg = false;
5681 case Operator.Addition:
5682 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5683 method_name = "AddChecked";
5685 method_name = "Add";
5687 case Operator.BitwiseAnd:
5688 method_name = "And";
5690 case Operator.BitwiseOr:
5693 case Operator.Division:
5694 method_name = "Divide";
5696 case Operator.Equality:
5697 method_name = "Equal";
5700 case Operator.ExclusiveOr:
5701 method_name = "ExclusiveOr";
5703 case Operator.GreaterThan:
5704 method_name = "GreaterThan";
5707 case Operator.GreaterThanOrEqual:
5708 method_name = "GreaterThanOrEqual";
5711 case Operator.Inequality:
5712 method_name = "NotEqual";
5715 case Operator.LeftShift:
5716 method_name = "LeftShift";
5718 case Operator.LessThan:
5719 method_name = "LessThan";
5722 case Operator.LessThanOrEqual:
5723 method_name = "LessThanOrEqual";
5726 case Operator.LogicalAnd:
5727 method_name = "AndAlso";
5729 case Operator.LogicalOr:
5730 method_name = "OrElse";
5732 case Operator.Modulus:
5733 method_name = "Modulo";
5735 case Operator.Multiply:
5736 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5737 method_name = "MultiplyChecked";
5739 method_name = "Multiply";
5741 case Operator.RightShift:
5742 method_name = "RightShift";
5744 case Operator.Subtraction:
5745 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5746 method_name = "SubtractChecked";
5748 method_name = "Subtract";
5752 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5755 Arguments args = new Arguments (2);
5756 args.Add (new Argument (left.CreateExpressionTree (ec)));
5757 args.Add (new Argument (right.CreateExpressionTree (ec)));
5758 if (method != null) {
5760 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5762 args.Add (new Argument (method));
5765 return CreateExpressionFactoryCall (ec, method_name, args);
5768 public override object Accept (StructuralVisitor visitor)
5770 return visitor.Visit (this);
5776 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5777 // b, c, d... may be strings or objects.
5779 public class StringConcat : Expression
5781 Arguments arguments;
5783 StringConcat (Location loc)
5786 arguments = new Arguments (2);
5789 public override bool ContainsEmitWithAwait ()
5791 return arguments.ContainsEmitWithAwait ();
5794 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5796 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5797 throw new ArgumentException ();
5799 var s = new StringConcat (loc);
5800 s.type = rc.BuiltinTypes.String;
5801 s.eclass = ExprClass.Value;
5803 s.Append (rc, left);
5804 s.Append (rc, right);
5808 public override Expression CreateExpressionTree (ResolveContext ec)
5810 Argument arg = arguments [0];
5811 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5815 // Creates nested calls tree from an array of arguments used for IL emit
5817 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5819 Arguments concat_args = new Arguments (2);
5820 Arguments add_args = new Arguments (3);
5822 concat_args.Add (left);
5823 add_args.Add (new Argument (left_etree));
5825 concat_args.Add (arguments [pos]);
5826 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5828 var methods = GetConcatMethodCandidates ();
5829 if (methods == null)
5832 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5833 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5837 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5839 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5840 if (++pos == arguments.Count)
5843 left = new Argument (new EmptyExpression (method.ReturnType));
5844 return CreateExpressionAddCall (ec, left, expr, pos);
5847 protected override Expression DoResolve (ResolveContext ec)
5852 void Append (ResolveContext rc, Expression operand)
5857 StringConstant sc = operand as StringConstant;
5859 if (arguments.Count != 0) {
5860 Argument last_argument = arguments [arguments.Count - 1];
5861 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5862 if (last_expr_constant != null) {
5863 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5869 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5871 StringConcat concat_oper = operand as StringConcat;
5872 if (concat_oper != null) {
5873 arguments.AddRange (concat_oper.arguments);
5878 arguments.Add (new Argument (operand));
5881 IList<MemberSpec> GetConcatMethodCandidates ()
5883 return MemberCache.FindMembers (type, "Concat", true);
5886 public override void Emit (EmitContext ec)
5888 // Optimize by removing any extra null arguments, they are no-op
5889 for (int i = 0; i < arguments.Count; ++i) {
5890 if (arguments[i].Expr is NullConstant)
5891 arguments.RemoveAt (i--);
5894 var members = GetConcatMethodCandidates ();
5895 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5896 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5897 if (method != null) {
5898 var call = new CallEmitter ();
5899 call.EmitPredefined (ec, method, arguments, false);
5903 public override void FlowAnalysis (FlowAnalysisContext fc)
5905 arguments.FlowAnalysis (fc);
5908 public override SLE.Expression MakeExpression (BuilderContext ctx)
5910 if (arguments.Count != 2)
5911 throw new NotImplementedException ("arguments.Count != 2");
5913 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5914 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5919 // User-defined conditional logical operator
5921 public class ConditionalLogicalOperator : UserOperatorCall
5923 readonly bool is_and;
5924 Expression oper_expr;
5926 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5927 : base (oper, arguments, expr_tree, loc)
5929 this.is_and = is_and;
5930 eclass = ExprClass.Unresolved;
5933 protected override Expression DoResolve (ResolveContext ec)
5935 AParametersCollection pd = oper.Parameters;
5936 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5937 ec.Report.Error (217, loc,
5938 "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",
5939 oper.GetSignatureForError ());
5943 Expression left_dup = new EmptyExpression (type);
5944 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5945 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5946 if (op_true == null || op_false == null) {
5947 ec.Report.Error (218, loc,
5948 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5949 type.GetSignatureForError (), oper.GetSignatureForError ());
5953 oper_expr = is_and ? op_false : op_true;
5954 eclass = ExprClass.Value;
5958 public override void Emit (EmitContext ec)
5960 Label end_target = ec.DefineLabel ();
5963 // Emit and duplicate left argument
5965 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5966 if (right_contains_await) {
5967 arguments[0] = arguments[0].EmitToField (ec, false);
5968 arguments[0].Expr.Emit (ec);
5970 arguments[0].Expr.Emit (ec);
5971 ec.Emit (OpCodes.Dup);
5972 arguments.RemoveAt (0);
5975 oper_expr.EmitBranchable (ec, end_target, true);
5979 if (right_contains_await) {
5981 // Special handling when right expression contains await and left argument
5982 // could not be left on stack before logical branch
5984 Label skip_left_load = ec.DefineLabel ();
5985 ec.Emit (OpCodes.Br_S, skip_left_load);
5986 ec.MarkLabel (end_target);
5987 arguments[0].Expr.Emit (ec);
5988 ec.MarkLabel (skip_left_load);
5990 ec.MarkLabel (end_target);
5995 public class PointerArithmetic : Expression {
5996 Expression left, right;
5997 readonly Binary.Operator op;
6000 // We assume that `l' is always a pointer
6002 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
6011 public override bool ContainsEmitWithAwait ()
6013 throw new NotImplementedException ();
6016 public override Expression CreateExpressionTree (ResolveContext ec)
6018 Error_PointerInsideExpressionTree (ec);
6022 protected override Expression DoResolve (ResolveContext ec)
6024 eclass = ExprClass.Variable;
6026 var pc = left.Type as PointerContainer;
6027 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6028 Error_VoidPointerOperation (ec);
6035 public override void Emit (EmitContext ec)
6037 TypeSpec op_type = left.Type;
6039 // It must be either array or fixed buffer
6041 if (TypeManager.HasElementType (op_type)) {
6042 element = TypeManager.GetElementType (op_type);
6044 FieldExpr fe = left as FieldExpr;
6046 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6051 int size = BuiltinTypeSpec.GetSize(element);
6052 TypeSpec rtype = right.Type;
6054 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6056 // handle (pointer - pointer)
6060 ec.Emit (OpCodes.Sub);
6064 ec.Emit (OpCodes.Sizeof, element);
6067 ec.Emit (OpCodes.Div);
6069 ec.Emit (OpCodes.Conv_I8);
6072 // handle + and - on (pointer op int)
6074 Constant left_const = left as Constant;
6075 if (left_const != null) {
6077 // Optimize ((T*)null) pointer operations
6079 if (left_const.IsDefaultValue) {
6080 left = EmptyExpression.Null;
6088 var right_const = right as Constant;
6089 if (right_const != null) {
6091 // Optimize 0-based arithmetic
6093 if (right_const.IsDefaultValue)
6097 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6099 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6101 // TODO: Should be the checks resolve context sensitive?
6102 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6103 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6109 if (right_const == null) {
6110 switch (rtype.BuiltinType) {
6111 case BuiltinTypeSpec.Type.SByte:
6112 case BuiltinTypeSpec.Type.Byte:
6113 case BuiltinTypeSpec.Type.Short:
6114 case BuiltinTypeSpec.Type.UShort:
6115 case BuiltinTypeSpec.Type.Int:
6116 ec.Emit (OpCodes.Conv_I);
6118 case BuiltinTypeSpec.Type.UInt:
6119 ec.Emit (OpCodes.Conv_U);
6124 if (right_const == null && size != 1){
6126 ec.Emit (OpCodes.Sizeof, element);
6129 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6130 ec.Emit (OpCodes.Conv_I8);
6132 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6135 if (left_const == null) {
6136 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6137 ec.Emit (OpCodes.Conv_I);
6138 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6139 ec.Emit (OpCodes.Conv_U);
6141 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6148 // A boolean-expression is an expression that yields a result
6151 public class BooleanExpression : ShimExpression
6153 public BooleanExpression (Expression expr)
6156 this.loc = expr.Location;
6159 public override Expression CreateExpressionTree (ResolveContext ec)
6161 // TODO: We should emit IsTrue (v4) instead of direct user operator
6162 // call but that would break csc compatibility
6163 return base.CreateExpressionTree (ec);
6166 protected override Expression DoResolve (ResolveContext ec)
6168 // A boolean-expression is required to be of a type
6169 // that can be implicitly converted to bool or of
6170 // a type that implements operator true
6172 expr = expr.Resolve (ec);
6176 Assign ass = expr as Assign;
6177 if (ass != null && ass.Source is Constant) {
6178 ec.Report.Warning (665, 3, loc,
6179 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6185 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6186 Arguments args = new Arguments (1);
6187 args.Add (new Argument (expr));
6188 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6191 type = ec.BuiltinTypes.Bool;
6192 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6193 if (converted != null)
6197 // If no implicit conversion to bool exists, try using `operator true'
6199 converted = GetOperatorTrue (ec, expr, loc);
6200 if (converted == null) {
6201 expr.Error_ValueCannotBeConverted (ec, type, false);
6208 public override object Accept (StructuralVisitor visitor)
6210 return visitor.Visit (this);
6214 public class BooleanExpressionFalse : Unary
6216 public BooleanExpressionFalse (Expression expr)
6217 : base (Operator.LogicalNot, expr, expr.Location)
6221 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6223 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6228 /// Implements the ternary conditional operator (?:)
6230 public class Conditional : Expression {
6231 Expression expr, true_expr, false_expr;
6233 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6236 this.true_expr = true_expr;
6237 this.false_expr = false_expr;
6243 public Expression Expr {
6249 public Expression TrueExpr {
6255 public Expression FalseExpr {
6263 public override bool ContainsEmitWithAwait ()
6265 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6268 public override Expression CreateExpressionTree (ResolveContext ec)
6270 Arguments args = new Arguments (3);
6271 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6272 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6273 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6274 return CreateExpressionFactoryCall (ec, "Condition", args);
6277 protected override Expression DoResolve (ResolveContext ec)
6279 expr = expr.Resolve (ec);
6280 true_expr = true_expr.Resolve (ec);
6281 false_expr = false_expr.Resolve (ec);
6283 if (true_expr == null || false_expr == null || expr == null)
6286 eclass = ExprClass.Value;
6287 TypeSpec true_type = true_expr.Type;
6288 TypeSpec false_type = false_expr.Type;
6292 // First, if an implicit conversion exists from true_expr
6293 // to false_expr, then the result type is of type false_expr.Type
6295 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6296 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6297 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6299 // Check if both can convert implicitly to each other's type
6303 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6304 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6306 // LAMESPEC: There seems to be hardcoded promotition to int type when
6307 // both sides are numeric constants and one side is int constant and
6308 // other side is numeric constant convertible to int.
6310 // var res = condition ? (short)1 : 1;
6312 // Type of res is int even if according to the spec the conversion is
6313 // ambiguous because 1 literal can be converted to short.
6315 if (conv_false_expr != null) {
6316 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6318 conv_false_expr = null;
6319 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6320 conv_false_expr = null;
6324 if (conv_false_expr != null) {
6325 ec.Report.Error (172, true_expr.Location,
6326 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6327 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6332 if (true_expr.Type != type)
6333 true_expr = EmptyCast.Create (true_expr, type);
6334 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6337 if (false_type != InternalType.ErrorType) {
6338 ec.Report.Error (173, true_expr.Location,
6339 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6340 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6346 Constant c = expr as Constant;
6348 bool is_false = c.IsDefaultValue;
6351 // Don't issue the warning for constant expressions
6353 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6354 // CSC: Missing warning
6355 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6358 return ReducedExpression.Create (
6359 is_false ? false_expr : true_expr, this,
6360 false_expr is Constant && true_expr is Constant).Resolve (ec);
6366 public override void Emit (EmitContext ec)
6368 Label false_target = ec.DefineLabel ();
6369 Label end_target = ec.DefineLabel ();
6371 expr.EmitBranchable (ec, false_target, false);
6372 true_expr.Emit (ec);
6375 // Verifier doesn't support interface merging. When there are two types on
6376 // the stack without common type hint and the common type is an interface.
6377 // Use temporary local to give verifier hint on what type to unify the stack
6379 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6380 var temp = ec.GetTemporaryLocal (type);
6381 ec.Emit (OpCodes.Stloc, temp);
6382 ec.Emit (OpCodes.Ldloc, temp);
6383 ec.FreeTemporaryLocal (temp, type);
6386 ec.Emit (OpCodes.Br, end_target);
6387 ec.MarkLabel (false_target);
6388 false_expr.Emit (ec);
6389 ec.MarkLabel (end_target);
6392 public override void FlowAnalysis (FlowAnalysisContext fc)
6394 expr.FlowAnalysisConditional (fc);
6395 var expr_true = fc.DefiniteAssignmentOnTrue;
6396 var expr_false = fc.DefiniteAssignmentOnFalse;
6398 fc.BranchDefiniteAssignment (expr_true);
6399 true_expr.FlowAnalysis (fc);
6400 var true_fc = fc.DefiniteAssignment;
6402 fc.BranchDefiniteAssignment (expr_false);
6403 false_expr.FlowAnalysis (fc);
6405 fc.DefiniteAssignment &= true_fc;
6408 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6410 expr.FlowAnalysisConditional (fc);
6411 var expr_true = fc.DefiniteAssignmentOnTrue;
6412 var expr_false = fc.DefiniteAssignmentOnFalse;
6414 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6415 true_expr.FlowAnalysisConditional (fc);
6416 var true_fc = fc.DefiniteAssignment;
6417 var true_da_true = fc.DefiniteAssignmentOnTrue;
6418 var true_da_false = fc.DefiniteAssignmentOnFalse;
6420 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6421 false_expr.FlowAnalysisConditional (fc);
6423 fc.DefiniteAssignment &= true_fc;
6424 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6425 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6428 protected override void CloneTo (CloneContext clonectx, Expression t)
6430 Conditional target = (Conditional) t;
6432 target.expr = expr.Clone (clonectx);
6433 target.true_expr = true_expr.Clone (clonectx);
6434 target.false_expr = false_expr.Clone (clonectx);
6438 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6440 LocalTemporary temp;
6443 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6444 public abstract void SetHasAddressTaken ();
6446 public abstract bool IsLockedByStatement { get; set; }
6448 public abstract bool IsFixed { get; }
6449 public abstract bool IsRef { get; }
6450 public abstract string Name { get; }
6453 // Variable IL data, it has to be protected to encapsulate hoisted variables
6455 protected abstract ILocalVariable Variable { get; }
6458 // Variable flow-analysis data
6460 public abstract VariableInfo VariableInfo { get; }
6463 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6465 HoistedVariable hv = GetHoistedVariable (ec);
6467 hv.AddressOf (ec, mode);
6471 Variable.EmitAddressOf (ec);
6474 public override bool ContainsEmitWithAwait ()
6479 public override Expression CreateExpressionTree (ResolveContext ec)
6481 HoistedVariable hv = GetHoistedVariable (ec);
6483 return hv.CreateExpressionTree ();
6485 Arguments arg = new Arguments (1);
6486 arg.Add (new Argument (this));
6487 return CreateExpressionFactoryCall (ec, "Constant", arg);
6490 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6492 if (IsLockedByStatement) {
6493 rc.Report.Warning (728, 2, loc,
6494 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6501 public override void Emit (EmitContext ec)
6506 public override void EmitSideEffect (EmitContext ec)
6512 // This method is used by parameters that are references, that are
6513 // being passed as references: we only want to pass the pointer (that
6514 // is already stored in the parameter, not the address of the pointer,
6515 // and not the value of the variable).
6517 public void EmitLoad (EmitContext ec)
6522 public void Emit (EmitContext ec, bool leave_copy)
6524 HoistedVariable hv = GetHoistedVariable (ec);
6526 hv.Emit (ec, leave_copy);
6534 // If we are a reference, we loaded on the stack a pointer
6535 // Now lets load the real value
6537 ec.EmitLoadFromPtr (type);
6541 ec.Emit (OpCodes.Dup);
6544 temp = new LocalTemporary (Type);
6550 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6551 bool prepare_for_load)
6553 HoistedVariable hv = GetHoistedVariable (ec);
6555 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6559 New n_source = source as New;
6560 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6561 if (!n_source.Emit (ec, this)) {
6565 ec.EmitLoadFromPtr (type);
6577 ec.Emit (OpCodes.Dup);
6579 temp = new LocalTemporary (Type);
6585 ec.EmitStoreFromPtr (type);
6587 Variable.EmitAssign (ec);
6595 public override Expression EmitToField (EmitContext ec)
6597 HoistedVariable hv = GetHoistedVariable (ec);
6599 return hv.EmitToField (ec);
6602 return base.EmitToField (ec);
6605 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6607 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6610 public HoistedVariable GetHoistedVariable (EmitContext ec)
6612 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6615 public override string GetSignatureForError ()
6620 public bool IsHoisted {
6621 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6626 // Resolved reference to a local variable
6628 public class LocalVariableReference : VariableReference
6630 public LocalVariable local_info;
6632 public LocalVariableReference (LocalVariable li, Location l)
6634 this.local_info = li;
6638 public override VariableInfo VariableInfo {
6639 get { return local_info.VariableInfo; }
6642 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6644 return local_info.HoistedVariant;
6650 // A local variable is always fixed
6652 public override bool IsFixed {
6658 public override bool IsLockedByStatement {
6660 return local_info.IsLocked;
6663 local_info.IsLocked = value;
6667 public override bool IsRef {
6668 get { return false; }
6671 public override string Name {
6672 get { return local_info.Name; }
6677 public override void FlowAnalysis (FlowAnalysisContext fc)
6679 VariableInfo variable_info = VariableInfo;
6680 if (variable_info == null)
6683 if (fc.IsDefinitelyAssigned (variable_info))
6686 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6687 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6690 public override void SetHasAddressTaken ()
6692 local_info.SetHasAddressTaken ();
6695 void DoResolveBase (ResolveContext ec)
6697 eclass = ExprClass.Variable;
6698 type = local_info.Type;
6701 // If we are referencing a variable from the external block
6702 // flag it for capturing
6704 if (ec.MustCaptureVariable (local_info)) {
6705 if (local_info.AddressTaken) {
6706 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6707 } else if (local_info.IsFixed) {
6708 ec.Report.Error (1764, loc,
6709 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6710 GetSignatureForError ());
6713 if (ec.IsVariableCapturingRequired) {
6714 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6715 storey.CaptureLocalVariable (ec, local_info);
6720 protected override Expression DoResolve (ResolveContext ec)
6722 local_info.SetIsUsed ();
6726 if (local_info.Type == InternalType.VarOutType) {
6727 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6728 GetSignatureForError ());
6730 type = InternalType.ErrorType;
6736 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6739 // Don't be too pedantic when variable is used as out param or for some broken code
6740 // which uses property/indexer access to run some initialization
6742 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6743 local_info.SetIsUsed ();
6745 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6746 if (rhs == EmptyExpression.LValueMemberAccess) {
6747 // CS1654 already reported
6751 if (rhs == EmptyExpression.OutAccess) {
6752 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6753 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6754 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6755 } else if (rhs == EmptyExpression.UnaryAddress) {
6756 code = 459; msg = "Cannot take the address of {1} `{0}'";
6758 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6760 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6764 if (eclass == ExprClass.Unresolved)
6767 return base.DoResolveLValue (ec, rhs);
6770 public override int GetHashCode ()
6772 return local_info.GetHashCode ();
6775 public override bool Equals (object obj)
6777 LocalVariableReference lvr = obj as LocalVariableReference;
6781 return local_info == lvr.local_info;
6784 protected override ILocalVariable Variable {
6785 get { return local_info; }
6788 public override string ToString ()
6790 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6793 protected override void CloneTo (CloneContext clonectx, Expression t)
6800 /// This represents a reference to a parameter in the intermediate
6803 public class ParameterReference : VariableReference
6805 protected ParametersBlock.ParameterInfo pi;
6807 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6815 public override bool IsLockedByStatement {
6820 pi.IsLocked = value;
6824 public override bool IsRef {
6825 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6828 bool HasOutModifier {
6829 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6832 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6834 return pi.Parameter.HoistedVariant;
6838 // A ref or out parameter is classified as a moveable variable, even
6839 // if the argument given for the parameter is a fixed variable
6841 public override bool IsFixed {
6842 get { return !IsRef; }
6845 public override string Name {
6846 get { return Parameter.Name; }
6849 public Parameter Parameter {
6850 get { return pi.Parameter; }
6853 public override VariableInfo VariableInfo {
6854 get { return pi.VariableInfo; }
6857 protected override ILocalVariable Variable {
6858 get { return Parameter; }
6863 public override void AddressOf (EmitContext ec, AddressOp mode)
6866 // ParameterReferences might already be a reference
6873 base.AddressOf (ec, mode);
6876 public override void SetHasAddressTaken ()
6878 Parameter.HasAddressTaken = true;
6881 bool DoResolveBase (ResolveContext ec)
6883 if (eclass != ExprClass.Unresolved)
6886 type = pi.ParameterType;
6887 eclass = ExprClass.Variable;
6890 // If we are referencing a parameter from the external block
6891 // flag it for capturing
6893 if (ec.MustCaptureVariable (pi)) {
6894 if (Parameter.HasAddressTaken)
6895 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6898 ec.Report.Error (1628, loc,
6899 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6900 Name, ec.CurrentAnonymousMethod.ContainerType);
6903 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6904 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6905 storey.CaptureParameter (ec, pi, this);
6912 public override int GetHashCode ()
6914 return Name.GetHashCode ();
6917 public override bool Equals (object obj)
6919 ParameterReference pr = obj as ParameterReference;
6923 return Name == pr.Name;
6926 protected override void CloneTo (CloneContext clonectx, Expression target)
6932 public override Expression CreateExpressionTree (ResolveContext ec)
6934 HoistedVariable hv = GetHoistedVariable (ec);
6936 return hv.CreateExpressionTree ();
6938 return Parameter.ExpressionTreeVariableReference ();
6941 protected override Expression DoResolve (ResolveContext ec)
6943 if (!DoResolveBase (ec))
6949 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6951 if (!DoResolveBase (ec))
6954 if (Parameter.HoistedVariant != null)
6955 Parameter.HoistedVariant.IsAssigned = true;
6957 return base.DoResolveLValue (ec, right_side);
6960 public override void FlowAnalysis (FlowAnalysisContext fc)
6962 VariableInfo variable_info = VariableInfo;
6963 if (variable_info == null)
6966 if (fc.IsDefinitelyAssigned (variable_info))
6969 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6970 fc.SetVariableAssigned (variable_info);
6975 /// Invocation of methods or delegates.
6977 public class Invocation : ExpressionStatement
6979 public class Predefined : Invocation
6981 public Predefined (MethodGroupExpr expr, Arguments arguments)
6982 : base (expr, arguments)
6987 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6989 mg.BestCandidate.CheckObsoleteness (rc, loc);
6995 protected Arguments arguments;
6996 protected Expression expr;
6997 protected MethodGroupExpr mg;
6998 bool conditional_access_receiver;
7000 public Invocation (Expression expr, Arguments arguments)
7003 this.arguments = arguments;
7005 loc = expr.Location;
7010 public Arguments Arguments {
7016 public Expression Exp {
7022 public MethodGroupExpr MethodGroup {
7028 public override Location StartLocation {
7030 return expr.StartLocation;
7036 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7038 if (MethodGroup == null)
7041 var candidate = MethodGroup.BestCandidate;
7042 if (candidate == null || !(candidate.IsStatic || Exp is This))
7045 var args_count = arguments == null ? 0 : arguments.Count;
7046 if (args_count != body.Parameters.Count)
7049 var lambda_parameters = body.Block.Parameters.FixedParameters;
7050 for (int i = 0; i < args_count; ++i) {
7051 var pr = arguments[i].Expr as ParameterReference;
7055 if (lambda_parameters[i] != pr.Parameter)
7058 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7062 var emg = MethodGroup as ExtensionMethodGroupExpr;
7064 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7065 if (candidate.IsGeneric) {
7066 var targs = new TypeExpression [candidate.Arity];
7067 for (int i = 0; i < targs.Length; ++i) {
7068 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7071 mg.SetTypeArguments (null, new TypeArguments (targs));
7080 protected override void CloneTo (CloneContext clonectx, Expression t)
7082 Invocation target = (Invocation) t;
7084 if (arguments != null)
7085 target.arguments = arguments.Clone (clonectx);
7087 target.expr = expr.Clone (clonectx);
7090 public override bool ContainsEmitWithAwait ()
7092 if (arguments != null && arguments.ContainsEmitWithAwait ())
7095 return mg.ContainsEmitWithAwait ();
7098 public override Expression CreateExpressionTree (ResolveContext ec)
7100 Expression instance = mg.IsInstance ?
7101 mg.InstanceExpression.CreateExpressionTree (ec) :
7102 new NullLiteral (loc);
7104 var args = Arguments.CreateForExpressionTree (ec, arguments,
7106 mg.CreateExpressionTree (ec));
7108 return CreateExpressionFactoryCall (ec, "Call", args);
7111 void ResolveConditionalAccessReceiver (ResolveContext rc)
7113 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7114 conditional_access_receiver = true;
7118 bool statement_resolve;
7119 public override ExpressionStatement ResolveStatement (BlockContext bc)
7121 statement_resolve = true;
7122 var es = base.ResolveStatement (bc);
7123 statement_resolve = false;
7128 protected override Expression DoResolve (ResolveContext rc)
7130 ResolveConditionalAccessReceiver (rc);
7131 return DoResolveInvocation (rc);
7134 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7136 var sn = expr as SimpleName;
7137 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
7138 var targets = new List<Expression> (arguments.Count);
7139 var variables = new List<LocalVariable> (arguments.Count);
7140 foreach (var arg in arguments) {
7141 var arg_sn = arg.Expr as SimpleName;
7142 if (arg_sn == null || arg_sn.Arity != 0) {
7143 rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
7144 return ErrorExpression.Instance;
7147 var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
7148 rc.CurrentBlock.AddLocalName (lv);
7151 targets.Add (new LocalVariableReference (lv, arg_sn.Location));
7154 var res = new TupleDeconstruct (targets, variables, right_side, loc);
7155 return res.Resolve (rc);
7158 return base.DoResolveLValue (rc, right_side);
7161 Expression DoResolveInvocation (ResolveContext ec)
7163 Expression member_expr;
7164 var atn = expr as ATypeNameExpression;
7166 var flags = default (ResolveContext.FlagsHandle);
7167 if (conditional_access_receiver)
7168 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7171 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7172 if (member_expr != null) {
7173 var name_of = member_expr as NameOf;
7174 if (name_of != null) {
7175 return name_of.ResolveOverload (ec, arguments);
7178 member_expr = member_expr.Resolve (ec);
7181 member_expr = expr.Resolve (ec);
7184 if (conditional_access_receiver)
7187 if (member_expr == null)
7191 // Next, evaluate all the expressions in the argument list
7193 bool dynamic_arg = false;
7194 if (arguments != null) {
7195 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7196 arguments.Resolve (ec, out dynamic_arg);
7200 TypeSpec expr_type = member_expr.Type;
7201 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7202 return DoResolveDynamic (ec, member_expr);
7204 mg = member_expr as MethodGroupExpr;
7205 Expression invoke = null;
7208 if (expr_type != null && expr_type.IsDelegate) {
7209 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7210 invoke = invoke.Resolve (ec);
7211 if (invoke == null || !dynamic_arg)
7214 if (member_expr is RuntimeValueExpression) {
7215 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7216 member_expr.Type.GetSignatureForError ());
7220 MemberExpr me = member_expr as MemberExpr;
7222 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7226 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7227 member_expr.GetSignatureForError ());
7232 if (invoke == null) {
7233 mg = DoResolveOverload (ec);
7239 return DoResolveDynamic (ec, member_expr);
7241 var method = mg.BestCandidate;
7242 type = mg.BestCandidateReturnType;
7243 if (conditional_access_receiver && !statement_resolve)
7244 type = LiftMemberType (ec, type);
7246 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7248 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7250 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7254 IsSpecialMethodInvocation (ec, method, loc);
7256 eclass = ExprClass.Value;
7260 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7263 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7265 args = dmb.Arguments;
7266 if (arguments != null)
7267 args.AddRange (arguments);
7268 } else if (mg == null) {
7269 if (arguments == null)
7270 args = new Arguments (1);
7274 args.Insert (0, new Argument (memberExpr));
7278 ec.Report.Error (1971, loc,
7279 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7284 if (arguments == null)
7285 args = new Arguments (1);
7289 MemberAccess ma = expr as MemberAccess;
7291 var inst = mg.InstanceExpression;
7292 var left_type = inst as TypeExpr;
7293 if (left_type != null) {
7294 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7295 } else if (inst != null) {
7297 // Any value type has to be pass as by-ref to get back the same
7298 // instance on which the member was called
7300 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7301 Argument.AType.Ref : Argument.AType.None;
7302 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7304 } else { // is SimpleName
7305 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7306 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7308 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7313 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7316 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7318 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7321 public override void FlowAnalysis (FlowAnalysisContext fc)
7323 if (mg.IsConditionallyExcluded)
7326 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7328 mg.FlowAnalysis (fc);
7330 if (arguments != null)
7331 arguments.FlowAnalysis (fc);
7333 if (conditional_access_receiver)
7334 fc.DefiniteAssignment = da;
7337 public override string GetSignatureForError ()
7339 return mg.GetSignatureForError ();
7342 public override bool HasConditionalAccess ()
7344 return expr.HasConditionalAccess ();
7348 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7349 // or the type dynamic, then the member is invocable
7351 public static bool IsMemberInvocable (MemberSpec member)
7353 switch (member.Kind) {
7354 case MemberKind.Event:
7356 case MemberKind.Field:
7357 case MemberKind.Property:
7358 var m = member as IInterfaceMemberSpec;
7359 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7365 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7367 if (!method.IsReservedMethod)
7370 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7373 ec.Report.SymbolRelatedToPreviousError (method);
7374 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7375 method.GetSignatureForError ());
7380 public override void Emit (EmitContext ec)
7382 if (mg.IsConditionallyExcluded)
7385 if (conditional_access_receiver)
7386 mg.EmitCall (ec, arguments, type, false);
7388 mg.EmitCall (ec, arguments, false);
7391 public override void EmitStatement (EmitContext ec)
7393 if (mg.IsConditionallyExcluded)
7396 if (conditional_access_receiver)
7397 mg.EmitCall (ec, arguments, type, true);
7399 mg.EmitCall (ec, arguments, true);
7402 public override SLE.Expression MakeExpression (BuilderContext ctx)
7404 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7407 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7410 throw new NotSupportedException ();
7412 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7413 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7417 public override object Accept (StructuralVisitor visitor)
7419 return visitor.Visit (this);
7424 // Implements simple new expression
7426 public class New : ExpressionStatement, IMemoryLocation
7428 protected Arguments arguments;
7431 // During bootstrap, it contains the RequestedType,
7432 // but if `type' is not null, it *might* contain a NewDelegate
7433 // (because of field multi-initialization)
7435 protected Expression RequestedType;
7437 protected MethodSpec method;
7439 public New (Expression requested_type, Arguments arguments, Location l)
7441 RequestedType = requested_type;
7442 this.arguments = arguments;
7447 public Arguments Arguments {
7454 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7456 public bool IsGeneratedStructConstructor {
7458 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7462 public Expression TypeExpression {
7464 return RequestedType;
7471 /// Converts complex core type syntax like 'new int ()' to simple constant
7473 public static Constant Constantify (TypeSpec t, Location loc)
7475 switch (t.BuiltinType) {
7476 case BuiltinTypeSpec.Type.Int:
7477 return new IntConstant (t, 0, loc);
7478 case BuiltinTypeSpec.Type.UInt:
7479 return new UIntConstant (t, 0, loc);
7480 case BuiltinTypeSpec.Type.Long:
7481 return new LongConstant (t, 0, loc);
7482 case BuiltinTypeSpec.Type.ULong:
7483 return new ULongConstant (t, 0, loc);
7484 case BuiltinTypeSpec.Type.Float:
7485 return new FloatConstant (t, 0, loc);
7486 case BuiltinTypeSpec.Type.Double:
7487 return new DoubleConstant (t, 0, loc);
7488 case BuiltinTypeSpec.Type.Short:
7489 return new ShortConstant (t, 0, loc);
7490 case BuiltinTypeSpec.Type.UShort:
7491 return new UShortConstant (t, 0, loc);
7492 case BuiltinTypeSpec.Type.SByte:
7493 return new SByteConstant (t, 0, loc);
7494 case BuiltinTypeSpec.Type.Byte:
7495 return new ByteConstant (t, 0, loc);
7496 case BuiltinTypeSpec.Type.Char:
7497 return new CharConstant (t, '\0', loc);
7498 case BuiltinTypeSpec.Type.Bool:
7499 return new BoolConstant (t, false, loc);
7500 case BuiltinTypeSpec.Type.Decimal:
7501 return new DecimalConstant (t, 0, loc);
7505 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7507 if (t.IsNullableType)
7508 return Nullable.LiftedNull.Create (t, loc);
7513 public override bool ContainsEmitWithAwait ()
7515 return arguments != null && arguments.ContainsEmitWithAwait ();
7519 // Checks whether the type is an interface that has the
7520 // [ComImport, CoClass] attributes and must be treated
7523 public Expression CheckComImport (ResolveContext ec)
7525 if (!type.IsInterface)
7529 // Turn the call into:
7530 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7532 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7533 if (real_class == null)
7536 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7537 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7538 return cast.Resolve (ec);
7541 public override Expression CreateExpressionTree (ResolveContext ec)
7544 if (method == null) {
7545 args = new Arguments (1);
7546 args.Add (new Argument (new TypeOf (type, loc)));
7548 args = Arguments.CreateForExpressionTree (ec,
7549 arguments, new TypeOfMethod (method, loc));
7552 return CreateExpressionFactoryCall (ec, "New", args);
7555 protected override Expression DoResolve (ResolveContext ec)
7557 if (RequestedType is TupleTypeExpr) {
7558 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
7561 type = RequestedType.ResolveAsType (ec);
7565 eclass = ExprClass.Value;
7567 if (type.IsPointer) {
7568 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7569 type.GetSignatureForError ());
7573 if (arguments == null) {
7574 Constant c = Constantify (type, RequestedType.Location);
7576 return ReducedExpression.Create (c, this);
7579 if (type.IsDelegate) {
7580 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7583 var tparam = type as TypeParameterSpec;
7584 if (tparam != null) {
7586 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7587 // where type parameter constraint is inflated to struct
7589 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7590 ec.Report.Error (304, loc,
7591 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7592 type.GetSignatureForError ());
7595 if ((arguments != null) && (arguments.Count != 0)) {
7596 ec.Report.Error (417, loc,
7597 "`{0}': cannot provide arguments when creating an instance of a variable type",
7598 type.GetSignatureForError ());
7604 if (type.IsStatic) {
7605 ec.Report.SymbolRelatedToPreviousError (type);
7606 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7610 if (type.IsInterface || type.IsAbstract){
7611 if (!TypeManager.IsGenericType (type)) {
7612 RequestedType = CheckComImport (ec);
7613 if (RequestedType != null)
7614 return RequestedType;
7617 ec.Report.SymbolRelatedToPreviousError (type);
7618 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7623 if (arguments != null) {
7624 arguments.Resolve (ec, out dynamic);
7629 method = ConstructorLookup (ec, type, ref arguments, loc);
7632 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7633 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7639 void DoEmitTypeParameter (EmitContext ec)
7641 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7645 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7646 ec.Emit (OpCodes.Call, ctor_factory);
7650 // This Emit can be invoked in two contexts:
7651 // * As a mechanism that will leave a value on the stack (new object)
7652 // * As one that wont (init struct)
7654 // If we are dealing with a ValueType, we have a few
7655 // situations to deal with:
7657 // * The target is a ValueType, and we have been provided
7658 // the instance (this is easy, we are being assigned).
7660 // * The target of New is being passed as an argument,
7661 // to a boxing operation or a function that takes a
7664 // In this case, we need to create a temporary variable
7665 // that is the argument of New.
7667 // Returns whether a value is left on the stack
7669 // *** Implementation note ***
7671 // To benefit from this optimization, each assignable expression
7672 // has to manually cast to New and call this Emit.
7674 // TODO: It's worth to implement it for arrays and fields
7676 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7678 bool is_value_type = type.IsStructOrEnum;
7679 VariableReference vr = target as VariableReference;
7681 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7683 if (target != null && is_value_type && (vr != null || method == null)) {
7684 if (prepare_await) {
7685 arguments = arguments.Emit (ec, false, true);
7686 prepare_await = false;
7689 target.AddressOf (ec, AddressOp.Store);
7690 } else if (vr != null && vr.IsRef) {
7694 if (arguments != null) {
7696 arguments = arguments.Emit (ec, false, true);
7698 arguments.Emit (ec);
7701 if (is_value_type) {
7702 if (method == null) {
7703 ec.Emit (OpCodes.Initobj, type);
7708 ec.MarkCallEntry (loc);
7709 ec.Emit (OpCodes.Call, method);
7714 if (type is TypeParameterSpec) {
7715 DoEmitTypeParameter (ec);
7719 ec.MarkCallEntry (loc);
7720 ec.Emit (OpCodes.Newobj, method);
7724 public override void Emit (EmitContext ec)
7726 LocalTemporary v = null;
7727 if (method == null && type.IsStructOrEnum) {
7728 // TODO: Use temporary variable from pool
7729 v = new LocalTemporary (type);
7736 public override void EmitStatement (EmitContext ec)
7738 LocalTemporary v = null;
7739 if (method == null && TypeSpec.IsValueType (type)) {
7740 // TODO: Use temporary variable from pool
7741 v = new LocalTemporary (type);
7745 ec.Emit (OpCodes.Pop);
7748 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7753 public override void FlowAnalysis (FlowAnalysisContext fc)
7755 if (arguments != null)
7756 arguments.FlowAnalysis (fc);
7759 public void AddressOf (EmitContext ec, AddressOp mode)
7761 EmitAddressOf (ec, mode);
7764 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7766 LocalTemporary value_target = new LocalTemporary (type);
7768 if (type is TypeParameterSpec) {
7769 DoEmitTypeParameter (ec);
7770 value_target.Store (ec);
7771 value_target.AddressOf (ec, mode);
7772 return value_target;
7775 value_target.AddressOf (ec, AddressOp.Store);
7777 if (method == null) {
7778 ec.Emit (OpCodes.Initobj, type);
7780 if (arguments != null)
7781 arguments.Emit (ec);
7783 ec.Emit (OpCodes.Call, method);
7786 value_target.AddressOf (ec, mode);
7787 return value_target;
7790 protected override void CloneTo (CloneContext clonectx, Expression t)
7792 New target = (New) t;
7794 target.RequestedType = RequestedType.Clone (clonectx);
7795 if (arguments != null){
7796 target.arguments = arguments.Clone (clonectx);
7800 public override SLE.Expression MakeExpression (BuilderContext ctx)
7803 return base.MakeExpression (ctx);
7805 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7809 public override object Accept (StructuralVisitor visitor)
7811 return visitor.Visit (this);
7816 // Array initializer expression, the expression is allowed in
7817 // variable or field initialization only which makes it tricky as
7818 // the type has to be infered based on the context either from field
7819 // type or variable type (think of multiple declarators)
7821 public class ArrayInitializer : Expression
7823 List<Expression> elements;
7824 BlockVariable variable;
7826 public ArrayInitializer (List<Expression> init, Location loc)
7832 public ArrayInitializer (int count, Location loc)
7833 : this (new List<Expression> (count), loc)
7837 public ArrayInitializer (Location loc)
7845 get { return elements.Count; }
7848 public List<Expression> Elements {
7854 public Expression this [int index] {
7856 return elements [index];
7860 public BlockVariable VariableDeclaration {
7871 public void Add (Expression expr)
7873 elements.Add (expr);
7876 public override bool ContainsEmitWithAwait ()
7878 throw new NotSupportedException ();
7881 public override Expression CreateExpressionTree (ResolveContext ec)
7883 throw new NotSupportedException ("ET");
7886 protected override void CloneTo (CloneContext clonectx, Expression t)
7888 var target = (ArrayInitializer) t;
7890 target.elements = new List<Expression> (elements.Count);
7891 foreach (var element in elements)
7892 target.elements.Add (element.Clone (clonectx));
7895 protected override Expression DoResolve (ResolveContext rc)
7897 var current_field = rc.CurrentMemberDefinition as FieldBase;
7898 TypeExpression type;
7899 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7900 type = new TypeExpression (current_field.MemberType, current_field.Location);
7901 } else if (variable != null) {
7902 if (variable.TypeExpression is VarExpr) {
7903 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7904 return EmptyExpression.Null;
7907 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7909 throw new NotImplementedException ("Unexpected array initializer context");
7912 return new ArrayCreation (type, this).Resolve (rc);
7915 public override void Emit (EmitContext ec)
7917 throw new InternalErrorException ("Missing Resolve call");
7920 public override void FlowAnalysis (FlowAnalysisContext fc)
7922 throw new InternalErrorException ("Missing Resolve call");
7925 public override object Accept (StructuralVisitor visitor)
7927 return visitor.Visit (this);
7932 /// 14.5.10.2: Represents an array creation expression.
7936 /// There are two possible scenarios here: one is an array creation
7937 /// expression that specifies the dimensions and optionally the
7938 /// initialization data and the other which does not need dimensions
7939 /// specified but where initialization data is mandatory.
7941 public class ArrayCreation : Expression
7943 FullNamedExpression requested_base_type;
7944 ArrayInitializer initializers;
7947 // The list of Argument types.
7948 // This is used to construct the `newarray' or constructor signature
7950 protected List<Expression> arguments;
7952 protected TypeSpec array_element_type;
7954 protected int dimensions;
7955 protected readonly ComposedTypeSpecifier rank;
7956 Expression first_emit;
7957 LocalTemporary first_emit_temp;
7959 protected List<Expression> array_data;
7961 Dictionary<int, int> bounds;
7964 // The number of constants in array initializers
7965 int const_initializers_count;
7966 bool only_constant_initializers;
7968 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7969 : this (requested_base_type, rank, initializers, l)
7971 arguments = new List<Expression> (exprs);
7972 num_arguments = arguments.Count;
7976 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7978 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7980 this.requested_base_type = requested_base_type;
7982 this.initializers = initializers;
7986 num_arguments = rank.Dimension;
7990 // For compiler generated single dimensional arrays only
7992 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7993 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7998 // For expressions like int[] foo = { 1, 2, 3 };
8000 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
8001 : this (requested_base_type, null, initializers, initializers.Location)
8005 public bool NoEmptyInterpolation { get; set; }
8007 public ComposedTypeSpecifier Rank {
8013 public FullNamedExpression TypeExpression {
8015 return this.requested_base_type;
8019 public ArrayInitializer Initializers {
8021 return this.initializers;
8025 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
8027 if (initializers != null && bounds == null) {
8029 // We use this to store all the data values in the order in which we
8030 // will need to store them in the byte blob later
8032 array_data = new List<Expression> (probe.Count);
8033 bounds = new Dictionary<int, int> ();
8036 if (specified_dims) {
8037 Expression a = arguments [idx];
8042 a = ConvertExpressionToArrayIndex (ec, a);
8048 if (initializers != null) {
8049 Constant c = a as Constant;
8050 if (c == null && a is ArrayIndexCast)
8051 c = ((ArrayIndexCast) a).Child as Constant;
8054 ec.Report.Error (150, a.Location, "A constant value is expected");
8060 value = System.Convert.ToInt32 (c.GetValue ());
8062 ec.Report.Error (150, a.Location, "A constant value is expected");
8066 // TODO: probe.Count does not fit ulong in
8067 if (value != probe.Count) {
8068 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8072 bounds[idx] = value;
8076 if (initializers == null)
8079 for (int i = 0; i < probe.Count; ++i) {
8081 if (o is ArrayInitializer) {
8082 var sub_probe = o as ArrayInitializer;
8083 if (idx + 1 >= dimensions){
8084 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8088 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8089 if (!bounds.ContainsKey(idx + 1))
8090 bounds[idx + 1] = sub_probe.Count;
8092 if (bounds[idx + 1] != sub_probe.Count) {
8093 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8097 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8100 } else if (child_bounds > 1) {
8101 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8103 Expression element = ResolveArrayElement (ec, o);
8104 if (element == null)
8107 // Initializers with the default values can be ignored
8108 Constant c = element as Constant;
8110 if (!c.IsDefaultInitializer (array_element_type)) {
8111 ++const_initializers_count;
8114 only_constant_initializers = false;
8117 array_data.Add (element);
8124 public override bool ContainsEmitWithAwait ()
8126 foreach (var arg in arguments) {
8127 if (arg.ContainsEmitWithAwait ())
8131 return InitializersContainAwait ();
8134 public override Expression CreateExpressionTree (ResolveContext ec)
8138 if (array_data == null) {
8139 args = new Arguments (arguments.Count + 1);
8140 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8141 foreach (Expression a in arguments)
8142 args.Add (new Argument (a.CreateExpressionTree (ec)));
8144 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8147 if (dimensions > 1) {
8148 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8152 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8153 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8154 if (array_data != null) {
8155 for (int i = 0; i < array_data.Count; ++i) {
8156 Expression e = array_data [i];
8157 args.Add (new Argument (e.CreateExpressionTree (ec)));
8161 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8164 void UpdateIndices (ResolveContext rc)
8167 for (var probe = initializers; probe != null;) {
8168 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8170 bounds[i++] = probe.Count;
8172 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8173 probe = (ArrayInitializer) probe[0];
8174 } else if (dimensions > i) {
8182 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8184 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8187 public override void FlowAnalysis (FlowAnalysisContext fc)
8189 foreach (var arg in arguments)
8190 arg.FlowAnalysis (fc);
8192 if (array_data != null) {
8193 foreach (var ad in array_data)
8194 ad.FlowAnalysis (fc);
8198 bool InitializersContainAwait ()
8200 if (array_data == null)
8203 foreach (var expr in array_data) {
8204 if (expr.ContainsEmitWithAwait ())
8211 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8213 element = element.Resolve (ec);
8214 if (element == null)
8217 var te = element as CompoundAssign.TargetExpression;
8219 for (int i = 1; i < initializers.Count; ++i) {
8220 if (initializers [i].ContainsEmitWithAwait ()) {
8221 te.RequiresEmitWithAwait = true;
8226 if (!te.RequiresEmitWithAwait) {
8227 if (first_emit != null)
8228 throw new InternalErrorException ("Can only handle one mutator at a time");
8229 first_emit = element;
8230 element = first_emit_temp = new LocalTemporary (element.Type);
8234 return Convert.ImplicitConversionRequired (
8235 ec, element, array_element_type, loc);
8238 protected bool ResolveInitializers (ResolveContext ec)
8241 only_constant_initializers = true;
8244 if (arguments != null) {
8246 for (int i = 0; i < arguments.Count; ++i) {
8247 res &= CheckIndices (ec, initializers, i, true, dimensions);
8248 if (initializers != null)
8255 arguments = new List<Expression> ();
8257 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8266 // Resolved the type of the array
8268 bool ResolveArrayType (ResolveContext ec)
8273 FullNamedExpression array_type_expr;
8274 if (num_arguments > 0) {
8275 array_type_expr = new ComposedCast (requested_base_type, rank);
8277 array_type_expr = requested_base_type;
8280 type = array_type_expr.ResolveAsType (ec);
8281 if (array_type_expr == null)
8284 var ac = type as ArrayContainer;
8286 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8290 array_element_type = ac.Element;
8291 dimensions = ac.Rank;
8296 protected override Expression DoResolve (ResolveContext ec)
8301 if (!ResolveArrayType (ec))
8305 // validate the initializers and fill in any missing bits
8307 if (!ResolveInitializers (ec))
8310 eclass = ExprClass.Value;
8314 byte [] MakeByteBlob ()
8319 int count = array_data.Count;
8321 TypeSpec element_type = array_element_type;
8322 if (element_type.IsEnum)
8323 element_type = EnumSpec.GetUnderlyingType (element_type);
8325 factor = BuiltinTypeSpec.GetSize (element_type);
8327 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8329 data = new byte [(count * factor + 3) & ~3];
8332 for (int i = 0; i < count; ++i) {
8333 var c = array_data[i] as Constant;
8339 object v = c.GetValue ();
8341 switch (element_type.BuiltinType) {
8342 case BuiltinTypeSpec.Type.Long:
8343 long lval = (long) v;
8345 for (int j = 0; j < factor; ++j) {
8346 data[idx + j] = (byte) (lval & 0xFF);
8350 case BuiltinTypeSpec.Type.ULong:
8351 ulong ulval = (ulong) v;
8353 for (int j = 0; j < factor; ++j) {
8354 data[idx + j] = (byte) (ulval & 0xFF);
8355 ulval = (ulval >> 8);
8358 case BuiltinTypeSpec.Type.Float:
8359 var fval = SingleConverter.SingleToInt32Bits((float) v);
8361 data[idx] = (byte) (fval & 0xff);
8362 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8363 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8364 data[idx + 3] = (byte) (fval >> 24);
8366 case BuiltinTypeSpec.Type.Double:
8367 element = BitConverter.GetBytes ((double) v);
8369 for (int j = 0; j < factor; ++j)
8370 data[idx + j] = element[j];
8372 // FIXME: Handle the ARM float format.
8373 if (!BitConverter.IsLittleEndian)
8374 System.Array.Reverse (data, idx, 8);
8376 case BuiltinTypeSpec.Type.Char:
8377 int chval = (int) ((char) v);
8379 data[idx] = (byte) (chval & 0xff);
8380 data[idx + 1] = (byte) (chval >> 8);
8382 case BuiltinTypeSpec.Type.Short:
8383 int sval = (int) ((short) v);
8385 data[idx] = (byte) (sval & 0xff);
8386 data[idx + 1] = (byte) (sval >> 8);
8388 case BuiltinTypeSpec.Type.UShort:
8389 int usval = (int) ((ushort) v);
8391 data[idx] = (byte) (usval & 0xff);
8392 data[idx + 1] = (byte) (usval >> 8);
8394 case BuiltinTypeSpec.Type.Int:
8397 data[idx] = (byte) (val & 0xff);
8398 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8399 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8400 data[idx + 3] = (byte) (val >> 24);
8402 case BuiltinTypeSpec.Type.UInt:
8403 uint uval = (uint) v;
8405 data[idx] = (byte) (uval & 0xff);
8406 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8407 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8408 data[idx + 3] = (byte) (uval >> 24);
8410 case BuiltinTypeSpec.Type.SByte:
8411 data[idx] = (byte) (sbyte) v;
8413 case BuiltinTypeSpec.Type.Byte:
8414 data[idx] = (byte) v;
8416 case BuiltinTypeSpec.Type.Bool:
8417 data[idx] = (byte) ((bool) v ? 1 : 0);
8419 case BuiltinTypeSpec.Type.Decimal:
8420 int[] bits = Decimal.GetBits ((decimal) v);
8423 // FIXME: For some reason, this doesn't work on the MS runtime.
8424 int[] nbits = new int[4];
8430 for (int j = 0; j < 4; j++) {
8431 data[p++] = (byte) (nbits[j] & 0xff);
8432 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8433 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8434 data[p++] = (byte) (nbits[j] >> 24);
8438 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8447 public override SLE.Expression MakeExpression (BuilderContext ctx)
8450 return base.MakeExpression (ctx);
8452 var initializers = new SLE.Expression [array_data.Count];
8453 for (var i = 0; i < initializers.Length; i++) {
8454 if (array_data [i] == null)
8455 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8457 initializers [i] = array_data [i].MakeExpression (ctx);
8460 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8465 // Emits the initializers for the array
8467 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8469 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8474 // First, the static data
8476 byte [] data = MakeByteBlob ();
8477 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8479 if (stackArray == null) {
8480 ec.Emit (OpCodes.Dup);
8482 stackArray.Emit (ec);
8485 ec.Emit (OpCodes.Ldtoken, fb);
8486 ec.Emit (OpCodes.Call, m);
8491 // Emits pieces of the array that can not be computed at compile
8492 // time (variables and string locations).
8494 // This always expect the top value on the stack to be the array
8496 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8498 int dims = bounds.Count;
8499 var current_pos = new int [dims];
8501 for (int i = 0; i < array_data.Count; i++){
8503 Expression e = array_data [i];
8504 var c = e as Constant;
8506 // Constant can be initialized via StaticInitializer
8507 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8511 if (stackArray != null) {
8512 if (e.ContainsEmitWithAwait ()) {
8513 e = e.EmitToField (ec);
8516 stackArray.EmitLoad (ec);
8518 ec.Emit (OpCodes.Dup);
8521 for (int idx = 0; idx < dims; idx++)
8522 ec.EmitInt (current_pos [idx]);
8525 // If we are dealing with a struct, get the
8526 // address of it, so we can store it.
8528 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8529 ec.Emit (OpCodes.Ldelema, etype);
8533 ec.EmitArrayStore ((ArrayContainer) type);
8539 for (int j = dims - 1; j >= 0; j--){
8541 if (current_pos [j] < bounds [j])
8543 current_pos [j] = 0;
8547 if (stackArray != null)
8548 stackArray.PrepareCleanup (ec);
8551 public override void Emit (EmitContext ec)
8553 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8556 var await_field = EmitToFieldSource (ec);
8557 if (await_field != null)
8558 await_field.Emit (ec);
8561 bool EmitOptimizedEmpty (EmitContext ec)
8563 if (arguments.Count != 1 || dimensions != 1)
8566 var c = arguments [0] as Constant;
8567 if (c == null || !c.IsZeroInteger)
8570 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8571 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8574 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8575 ec.Emit (OpCodes.Call, m);
8579 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8581 if (first_emit != null) {
8582 first_emit.Emit (ec);
8583 first_emit_temp.Store (ec);
8586 StackFieldExpr await_stack_field;
8587 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8588 await_stack_field = ec.GetTemporaryField (type);
8591 await_stack_field = null;
8594 EmitExpressionsList (ec, arguments);
8596 ec.EmitArrayNew ((ArrayContainer) type);
8598 if (initializers == null)
8599 return await_stack_field;
8601 if (await_stack_field != null)
8602 await_stack_field.EmitAssignFromStack (ec);
8606 // Emit static initializer for arrays which contain more than 2 items and
8607 // the static initializer will initialize at least 25% of array values or there
8608 // is more than 10 items to be initialized
8610 // NOTE: const_initializers_count does not contain default constant values.
8612 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8613 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8614 EmitStaticInitializers (ec, await_stack_field);
8616 if (!only_constant_initializers)
8617 EmitDynamicInitializers (ec, false, await_stack_field);
8621 EmitDynamicInitializers (ec, true, await_stack_field);
8624 if (first_emit_temp != null)
8625 first_emit_temp.Release (ec);
8627 return await_stack_field;
8630 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8632 // no multi dimensional or jagged arrays
8633 if (arguments.Count != 1 || array_element_type.IsArray) {
8634 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8638 // No array covariance, except for array -> object
8639 if (type != targetType) {
8640 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8641 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8645 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8646 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8651 // Single dimensional array of 0 size
8652 if (array_data == null) {
8653 IntConstant ic = arguments[0] as IntConstant;
8654 if (ic == null || !ic.IsDefaultValue) {
8655 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8663 enc.Encode (array_data.Count);
8664 foreach (var element in array_data) {
8665 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8669 protected override void CloneTo (CloneContext clonectx, Expression t)
8671 ArrayCreation target = (ArrayCreation) t;
8673 if (requested_base_type != null)
8674 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8676 if (arguments != null){
8677 target.arguments = new List<Expression> (arguments.Count);
8678 foreach (Expression e in arguments)
8679 target.arguments.Add (e.Clone (clonectx));
8682 if (initializers != null)
8683 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8686 public override object Accept (StructuralVisitor visitor)
8688 return visitor.Visit (this);
8693 // Represents an implicitly typed array epxression
8695 class ImplicitlyTypedArrayCreation : ArrayCreation
8697 TypeInferenceContext best_type_inference;
8699 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8700 : base (null, rank, initializers, loc)
8704 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8705 : base (null, initializers, loc)
8709 protected override Expression DoResolve (ResolveContext ec)
8714 dimensions = rank.Dimension;
8716 best_type_inference = new TypeInferenceContext ();
8718 if (!ResolveInitializers (ec))
8721 best_type_inference.FixAllTypes (ec);
8722 array_element_type = best_type_inference.InferredTypeArguments[0];
8723 best_type_inference = null;
8725 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
8726 ec.Report.Error (826, loc,
8727 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8732 // At this point we found common base type for all initializer elements
8733 // but we have to be sure that all static initializer elements are of
8736 UnifyInitializerElement (ec);
8738 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8739 eclass = ExprClass.Value;
8744 // Converts static initializer only
8746 void UnifyInitializerElement (ResolveContext ec)
8748 for (int i = 0; i < array_data.Count; ++i) {
8749 Expression e = array_data[i];
8751 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8755 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8757 element = element.Resolve (ec);
8758 if (element != null)
8759 best_type_inference.AddCommonTypeBound (element.Type);
8765 sealed class CompilerGeneratedThis : This
8767 public CompilerGeneratedThis (TypeSpec type, Location loc)
8773 protected override Expression DoResolve (ResolveContext rc)
8775 eclass = ExprClass.Variable;
8777 var block = rc.CurrentBlock;
8778 if (block != null) {
8779 var top = block.ParametersBlock.TopBlock;
8780 if (top.ThisVariable != null)
8781 variable_info = top.ThisVariable.VariableInfo;
8788 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8790 return DoResolve (rc);
8793 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8800 /// Represents the `this' construct
8803 public class This : VariableReference
8805 sealed class ThisVariable : ILocalVariable
8807 public static readonly ILocalVariable Instance = new ThisVariable ();
8809 public void Emit (EmitContext ec)
8814 public void EmitAssign (EmitContext ec)
8816 throw new InvalidOperationException ();
8819 public void EmitAddressOf (EmitContext ec)
8825 protected VariableInfo variable_info;
8827 public This (Location loc)
8834 public override string Name {
8835 get { return "this"; }
8838 public override bool IsLockedByStatement {
8846 public override bool IsRef {
8847 get { return type.IsStruct; }
8850 public override bool IsSideEffectFree {
8856 protected override ILocalVariable Variable {
8857 get { return ThisVariable.Instance; }
8860 public override VariableInfo VariableInfo {
8861 get { return variable_info; }
8864 public override bool IsFixed {
8865 get { return false; }
8870 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8873 // It's null for all cases when we don't need to check `this'
8874 // definitive assignment
8876 if (variable_info == null)
8879 if (fc.IsDefinitelyAssigned (variable_info))
8882 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8885 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8887 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8888 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8889 } else if (ec.CurrentAnonymousMethod != null) {
8890 ec.Report.Error (1673, loc,
8891 "Anonymous methods inside structs cannot access instance members of `this'. " +
8892 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8894 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8898 public override void FlowAnalysis (FlowAnalysisContext fc)
8900 CheckStructThisDefiniteAssignment (fc);
8903 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8908 AnonymousMethodStorey storey = ae.Storey;
8909 return storey != null ? storey.HoistedThis : null;
8912 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8914 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8917 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8920 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8926 public virtual void ResolveBase (ResolveContext ec)
8928 eclass = ExprClass.Variable;
8929 type = ec.CurrentType;
8931 if (!IsThisAvailable (ec, false)) {
8932 Error_ThisNotAvailable (ec);
8936 var block = ec.CurrentBlock;
8937 if (block != null) {
8938 var top = block.ParametersBlock.TopBlock;
8939 if (top.ThisVariable != null)
8940 variable_info = top.ThisVariable.VariableInfo;
8942 AnonymousExpression am = ec.CurrentAnonymousMethod;
8943 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8945 // Hoisted this is almost like hoisted variable but not exactly. When
8946 // there is no variable hoisted we can simply emit an instance method
8947 // without lifting this into a storey. Unfotunatelly this complicates
8948 // things in other cases because we don't know where this will be hoisted
8949 // until top-level block is fully resolved
8951 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8952 am.SetHasThisAccess ();
8957 protected override Expression DoResolve (ResolveContext ec)
8963 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8965 if (eclass == ExprClass.Unresolved)
8969 if (right_side == EmptyExpression.UnaryAddress)
8970 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8971 else if (right_side == EmptyExpression.OutAccess)
8972 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8974 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8980 public override int GetHashCode()
8982 throw new NotImplementedException ();
8985 public override bool Equals (object obj)
8987 This t = obj as This;
8994 protected override void CloneTo (CloneContext clonectx, Expression t)
8999 public override void SetHasAddressTaken ()
9004 public override object Accept (StructuralVisitor visitor)
9006 return visitor.Visit (this);
9011 /// Represents the `__arglist' construct
9013 public class ArglistAccess : Expression
9015 public ArglistAccess (Location loc)
9020 protected override void CloneTo (CloneContext clonectx, Expression target)
9025 public override bool ContainsEmitWithAwait ()
9030 public override Expression CreateExpressionTree (ResolveContext ec)
9032 throw new NotSupportedException ("ET");
9035 protected override Expression DoResolve (ResolveContext ec)
9037 eclass = ExprClass.Variable;
9038 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
9040 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
9041 ec.Report.Error (190, loc,
9042 "The __arglist construct is valid only within a variable argument method");
9048 public override void Emit (EmitContext ec)
9050 ec.Emit (OpCodes.Arglist);
9053 public override object Accept (StructuralVisitor visitor)
9055 return visitor.Visit (this);
9060 /// Represents the `__arglist (....)' construct
9062 public class Arglist : Expression
9064 Arguments arguments;
9066 public Arglist (Location loc)
9071 public Arglist (Arguments args, Location l)
9077 public Arguments Arguments {
9083 public MetaType[] ArgumentTypes {
9085 if (arguments == null)
9086 return MetaType.EmptyTypes;
9088 var retval = new MetaType[arguments.Count];
9089 for (int i = 0; i < retval.Length; i++)
9090 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9096 public override bool ContainsEmitWithAwait ()
9098 throw new NotImplementedException ();
9101 public override Expression CreateExpressionTree (ResolveContext ec)
9103 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9107 protected override Expression DoResolve (ResolveContext ec)
9109 eclass = ExprClass.Variable;
9110 type = InternalType.Arglist;
9111 if (arguments != null) {
9112 bool dynamic; // Can be ignored as there is always only 1 overload
9113 arguments.Resolve (ec, out dynamic);
9119 public override void Emit (EmitContext ec)
9121 if (arguments != null)
9122 arguments.Emit (ec);
9125 protected override void CloneTo (CloneContext clonectx, Expression t)
9127 Arglist target = (Arglist) t;
9129 if (arguments != null)
9130 target.arguments = arguments.Clone (clonectx);
9133 public override object Accept (StructuralVisitor visitor)
9135 return visitor.Visit (this);
9139 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9141 FullNamedExpression texpr;
9143 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9150 public FullNamedExpression TypeExpression {
9156 public override bool ContainsEmitWithAwait ()
9161 public void AddressOf (EmitContext ec, AddressOp mode)
9164 ec.Emit (OpCodes.Refanyval, type);
9167 protected override Expression DoResolve (ResolveContext rc)
9169 expr = expr.Resolve (rc);
9170 type = texpr.ResolveAsType (rc);
9171 if (expr == null || type == null)
9174 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9175 eclass = ExprClass.Variable;
9179 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9181 return DoResolve (rc);
9184 public override void Emit (EmitContext ec)
9187 ec.Emit (OpCodes.Refanyval, type);
9188 ec.EmitLoadFromPtr (type);
9191 public void Emit (EmitContext ec, bool leave_copy)
9193 throw new NotImplementedException ();
9196 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9199 ec.Emit (OpCodes.Refanyval, type);
9202 LocalTemporary temporary = null;
9204 ec.Emit (OpCodes.Dup);
9205 temporary = new LocalTemporary (source.Type);
9206 temporary.Store (ec);
9209 ec.EmitStoreFromPtr (type);
9211 if (temporary != null) {
9212 temporary.Emit (ec);
9213 temporary.Release (ec);
9217 public override object Accept (StructuralVisitor visitor)
9219 return visitor.Visit (this);
9223 public class RefTypeExpr : ShimExpression
9225 public RefTypeExpr (Expression expr, Location loc)
9231 protected override Expression DoResolve (ResolveContext rc)
9233 expr = expr.Resolve (rc);
9237 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9241 type = rc.BuiltinTypes.Type;
9242 eclass = ExprClass.Value;
9246 public override void Emit (EmitContext ec)
9249 ec.Emit (OpCodes.Refanytype);
9250 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9252 ec.Emit (OpCodes.Call, m);
9255 public override object Accept (StructuralVisitor visitor)
9257 return visitor.Visit (this);
9261 public class MakeRefExpr : ShimExpression
9263 public MakeRefExpr (Expression expr, Location loc)
9269 public override bool ContainsEmitWithAwait ()
9271 throw new NotImplementedException ();
9274 protected override Expression DoResolve (ResolveContext rc)
9276 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9277 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9278 eclass = ExprClass.Value;
9282 public override void Emit (EmitContext ec)
9284 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9285 ec.Emit (OpCodes.Mkrefany, expr.Type);
9288 public override object Accept (StructuralVisitor visitor)
9290 return visitor.Visit (this);
9295 /// Implements the typeof operator
9297 public class TypeOf : Expression {
9298 FullNamedExpression QueriedType;
9301 public TypeOf (FullNamedExpression queried_type, Location l)
9303 QueriedType = queried_type;
9308 // Use this constructor for any compiler generated typeof expression
9310 public TypeOf (TypeSpec type, Location loc)
9312 this.typearg = type;
9318 public override bool IsSideEffectFree {
9324 public TypeSpec TypeArgument {
9330 public FullNamedExpression TypeExpression {
9339 protected override void CloneTo (CloneContext clonectx, Expression t)
9341 TypeOf target = (TypeOf) t;
9342 if (QueriedType != null)
9343 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9346 public override bool ContainsEmitWithAwait ()
9351 public override Expression CreateExpressionTree (ResolveContext ec)
9353 Arguments args = new Arguments (2);
9354 args.Add (new Argument (this));
9355 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9356 return CreateExpressionFactoryCall (ec, "Constant", args);
9359 protected override Expression DoResolve (ResolveContext ec)
9361 if (eclass != ExprClass.Unresolved)
9364 if (typearg == null) {
9366 // Pointer types are allowed without explicit unsafe, they are just tokens
9368 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9369 typearg = QueriedType.ResolveAsType (ec, true);
9372 if (typearg == null)
9375 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9376 ec.Report.Error (1962, QueriedType.Location,
9377 "The typeof operator cannot be used on the dynamic type");
9381 type = ec.BuiltinTypes.Type;
9383 // Even though what is returned is a type object, it's treated as a value by the compiler.
9384 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9385 eclass = ExprClass.Value;
9389 static bool ContainsDynamicType (TypeSpec type)
9391 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9394 var element_container = type as ElementTypeSpec;
9395 if (element_container != null)
9396 return ContainsDynamicType (element_container.Element);
9398 foreach (var t in type.TypeArguments) {
9399 if (ContainsDynamicType (t)) {
9407 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9409 // Target type is not System.Type therefore must be object
9410 // and we need to use different encoding sequence
9411 if (targetType != type)
9414 if (typearg is InflatedTypeSpec) {
9417 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9418 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9419 typearg.GetSignatureForError ());
9423 gt = gt.DeclaringType;
9424 } while (gt != null);
9427 if (ContainsDynamicType (typearg)) {
9428 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9432 enc.EncodeTypeName (typearg);
9435 public override void Emit (EmitContext ec)
9437 ec.Emit (OpCodes.Ldtoken, typearg);
9438 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9440 ec.Emit (OpCodes.Call, m);
9443 public override object Accept (StructuralVisitor visitor)
9445 return visitor.Visit (this);
9449 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9451 public TypeOfMethod (MethodSpec method, Location loc)
9452 : base (method, loc)
9456 protected override Expression DoResolve (ResolveContext ec)
9458 if (member.IsConstructor) {
9459 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9461 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9467 return base.DoResolve (ec);
9470 public override void Emit (EmitContext ec)
9472 ec.Emit (OpCodes.Ldtoken, member);
9475 ec.Emit (OpCodes.Castclass, type);
9478 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9480 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9483 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9485 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9489 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9491 protected readonly T member;
9493 protected TypeOfMember (T member, Location loc)
9495 this.member = member;
9499 public override bool IsSideEffectFree {
9505 public override bool ContainsEmitWithAwait ()
9510 public override Expression CreateExpressionTree (ResolveContext ec)
9512 Arguments args = new Arguments (2);
9513 args.Add (new Argument (this));
9514 args.Add (new Argument (new TypeOf (type, loc)));
9515 return CreateExpressionFactoryCall (ec, "Constant", args);
9518 protected override Expression DoResolve (ResolveContext ec)
9520 eclass = ExprClass.Value;
9524 public override void Emit (EmitContext ec)
9526 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9527 PredefinedMember<MethodSpec> p;
9529 p = GetTypeFromHandleGeneric (ec);
9530 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9532 p = GetTypeFromHandle (ec);
9535 var mi = p.Resolve (loc);
9537 ec.Emit (OpCodes.Call, mi);
9540 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9541 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9544 sealed class TypeOfField : TypeOfMember<FieldSpec>
9546 public TypeOfField (FieldSpec field, Location loc)
9551 protected override Expression DoResolve (ResolveContext ec)
9553 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9557 return base.DoResolve (ec);
9560 public override void Emit (EmitContext ec)
9562 ec.Emit (OpCodes.Ldtoken, member);
9566 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9568 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9571 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9573 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9578 /// Implements the sizeof expression
9580 public class SizeOf : Expression {
9581 readonly Expression texpr;
9582 TypeSpec type_queried;
9584 public SizeOf (Expression queried_type, Location l)
9586 this.texpr = queried_type;
9590 public override bool IsSideEffectFree {
9596 public Expression TypeExpression {
9602 public override bool ContainsEmitWithAwait ()
9607 public override Expression CreateExpressionTree (ResolveContext ec)
9609 Error_PointerInsideExpressionTree (ec);
9613 protected override Expression DoResolve (ResolveContext ec)
9615 type_queried = texpr.ResolveAsType (ec);
9616 if (type_queried == null)
9619 if (type_queried.IsEnum)
9620 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9622 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9624 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9627 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9632 ec.Report.Error (233, loc,
9633 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9634 type_queried.GetSignatureForError ());
9637 type = ec.BuiltinTypes.Int;
9638 eclass = ExprClass.Value;
9642 public override void Emit (EmitContext ec)
9644 ec.Emit (OpCodes.Sizeof, type_queried);
9647 protected override void CloneTo (CloneContext clonectx, Expression t)
9651 public override object Accept (StructuralVisitor visitor)
9653 return visitor.Visit (this);
9658 /// Implements the qualified-alias-member (::) expression.
9660 public class QualifiedAliasMember : MemberAccess
9662 readonly string alias;
9663 public static readonly string GlobalAlias = "global";
9665 public QualifiedAliasMember (string alias, string identifier, Location l)
9666 : base (null, identifier, l)
9671 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9672 : base (null, identifier, targs, l)
9677 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9678 : base (null, identifier, arity, l)
9683 public string Alias {
9689 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9691 if (alias == GlobalAlias)
9692 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9694 int errors = mc.Module.Compiler.Report.Errors;
9695 var expr = mc.LookupNamespaceAlias (alias);
9697 if (errors == mc.Module.Compiler.Report.Errors)
9698 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9706 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9708 expr = CreateExpressionFromAlias (mc);
9712 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9715 protected override Expression DoResolve (ResolveContext rc)
9717 return ResolveAsTypeOrNamespace (rc, false);
9720 public override string GetSignatureForError ()
9723 if (targs != null) {
9724 name = Name + "<" + targs.GetSignatureForError () + ">";
9727 return alias + "::" + name;
9730 public override bool HasConditionalAccess ()
9735 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9737 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9738 rc.Module.Compiler.Report.Error (687, loc,
9739 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9740 GetSignatureForError ());
9745 return DoResolve (rc);
9748 protected override void CloneTo (CloneContext clonectx, Expression t)
9753 public override object Accept (StructuralVisitor visitor)
9755 return visitor.Visit (this);
9760 /// Implements the member access expression
9762 public class MemberAccess : ATypeNameExpression
9764 protected Expression expr;
9766 public MemberAccess (Expression expr, string id)
9767 : base (id, expr.Location)
9772 public MemberAccess (Expression expr, string identifier, Location loc)
9773 : base (identifier, loc)
9778 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9779 : base (identifier, args, loc)
9784 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9785 : base (identifier, arity, loc)
9790 public Expression LeftExpression {
9796 public override Location StartLocation {
9798 return expr == null ? loc : expr.StartLocation;
9802 protected override Expression DoResolve (ResolveContext rc)
9804 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9806 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9811 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9813 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9815 if (e is TypeExpr) {
9816 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9821 e = e.ResolveLValue (rc, rhs);
9826 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9828 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9829 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9831 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9834 public override bool HasConditionalAccess ()
9836 return LeftExpression.HasConditionalAccess ();
9839 public static bool IsValidDotExpression (TypeSpec type)
9841 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9842 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9844 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9847 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9849 var sn = expr as SimpleName;
9850 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9853 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9856 // Resolve expression which does have type set as we need expression type
9857 // with disable flow analysis as we don't know whether left side expression
9858 // is used as variable or type
9860 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9861 expr = expr.Resolve (rc);
9862 } else if (expr is TypeParameterExpr) {
9863 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9867 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9868 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9869 expr = expr.Resolve (rc, flags);
9872 expr = expr.Resolve (rc, flags);
9879 var ns = expr as NamespaceExpression;
9881 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9883 if (retval == null) {
9884 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9889 if (HasTypeArguments)
9890 return new GenericTypeExpr (retval.Type, targs, loc);
9892 targs.Resolve (rc, false);
9898 var cma = this as ConditionalMemberAccess;
9901 TypeSpec expr_type = expr.Type;
9902 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9903 me = expr as MemberExpr;
9905 me.ResolveInstanceExpression (rc, null);
9907 Arguments args = new Arguments (1);
9908 args.Add (new Argument (expr));
9911 return new DynamicConditionalMemberBinder (Name, args, loc);
9913 return new DynamicMemberBinder (Name, args, loc);
9917 if (!IsNullPropagatingValid (expr.Type)) {
9918 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9922 if (expr_type.IsNullableType) {
9923 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9924 expr_type = expr.Type;
9928 if (!IsValidDotExpression (expr_type)) {
9929 Error_OperatorCannotBeApplied (rc, expr_type);
9933 var lookup_arity = Arity;
9934 bool errorMode = false;
9935 Expression member_lookup;
9937 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9938 if (member_lookup == null) {
9940 // Try to look for extension method when member lookup failed
9942 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9943 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9944 if (methods != null) {
9945 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9946 if (HasTypeArguments) {
9947 if (!targs.Resolve (rc, false))
9950 emg.SetTypeArguments (rc, targs);
9954 emg.ConditionalAccess = true;
9956 // TODO: it should really skip the checks bellow
9957 return emg.Resolve (rc);
9963 if (member_lookup == null) {
9964 var dep = expr_type.GetMissingDependencies ();
9966 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9967 } else if (expr is TypeExpr) {
9968 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9970 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9976 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9977 // Leave it to overload resolution to report correct error
9978 } else if (!(member_lookup is TypeExpr)) {
9979 // TODO: rc.SymbolRelatedToPreviousError
9980 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9985 if (member_lookup != null)
9989 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9993 TypeExpr texpr = member_lookup as TypeExpr;
9994 if (texpr != null) {
9995 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9996 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9997 Name, texpr.GetSignatureForError ());
10000 if (!texpr.Type.IsAccessible (rc)) {
10001 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
10002 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
10006 if (HasTypeArguments) {
10007 return new GenericTypeExpr (member_lookup.Type, targs, loc);
10010 return member_lookup;
10013 me = member_lookup as MemberExpr;
10015 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
10020 me.ConditionalAccess = true;
10023 me = me.ResolveMemberAccess (rc, expr, sn);
10026 if (!targs.Resolve (rc, false))
10029 me.SetTypeArguments (rc, targs);
10035 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
10037 FullNamedExpression fexpr = expr as FullNamedExpression;
10038 if (fexpr == null) {
10039 expr.ResolveAsType (rc);
10043 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
10045 if (expr_resolved == null)
10048 var ns = expr_resolved as NamespaceExpression;
10050 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10052 if (retval == null) {
10053 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10054 } else if (Arity > 0) {
10055 if (HasTypeArguments) {
10056 retval = new GenericTypeExpr (retval.Type, targs, loc);
10057 if (retval.ResolveAsType (rc) == null)
10060 targs.Resolve (rc, allowUnboundTypeArguments);
10062 retval = new GenericOpenTypeExpr (retval.Type, loc);
10069 var tnew_expr = expr_resolved.ResolveAsType (rc);
10070 if (tnew_expr == null)
10073 TypeSpec expr_type = tnew_expr;
10074 if (TypeManager.IsGenericParameter (expr_type)) {
10075 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10076 tnew_expr.GetSignatureForError ());
10080 var qam = this as QualifiedAliasMember;
10082 rc.Module.Compiler.Report.Error (431, loc,
10083 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10088 TypeSpec nested = null;
10089 while (expr_type != null) {
10090 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10091 if (nested == null) {
10092 if (expr_type == tnew_expr) {
10093 Error_IdentifierNotFound (rc, expr_type);
10097 expr_type = tnew_expr;
10098 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10099 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10103 if (nested.IsAccessible (rc))
10107 // Keep looking after inaccessible candidate but only if
10108 // we are not in same context as the definition itself
10110 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10113 expr_type = expr_type.BaseType;
10118 if (HasTypeArguments) {
10119 texpr = new GenericTypeExpr (nested, targs, loc);
10121 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10123 texpr = new GenericOpenTypeExpr (nested, loc);
10125 } else if (expr_resolved is GenericOpenTypeExpr) {
10126 texpr = new GenericOpenTypeExpr (nested, loc);
10128 texpr = new TypeExpression (nested, loc);
10131 if (texpr.ResolveAsType (rc) == null)
10137 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10139 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10141 if (nested != null) {
10142 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10146 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10147 if (any_other_member != null) {
10148 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10152 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10153 Name, expr_type.GetSignatureForError ());
10156 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10158 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10161 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10163 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10164 ec.Report.SymbolRelatedToPreviousError (type);
10166 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10168 // a using directive or an assembly reference
10169 if (cand != null) {
10170 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10172 missing = "an assembly reference";
10175 ec.Report.Error (1061, loc,
10176 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10177 type.GetSignatureForError (), name, missing);
10181 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10184 public override string GetSignatureForError ()
10186 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10189 protected override void CloneTo (CloneContext clonectx, Expression t)
10191 MemberAccess target = (MemberAccess) t;
10193 target.expr = expr.Clone (clonectx);
10196 public override object Accept (StructuralVisitor visitor)
10198 return visitor.Visit (this);
10202 public class ConditionalMemberAccess : MemberAccess
10204 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10205 : base (expr, identifier, args, loc)
10209 public override bool HasConditionalAccess ()
10216 /// Implements checked expressions
10218 public class CheckedExpr : Expression {
10220 public Expression Expr;
10222 public CheckedExpr (Expression e, Location l)
10228 public override bool ContainsEmitWithAwait ()
10230 return Expr.ContainsEmitWithAwait ();
10233 public override Expression CreateExpressionTree (ResolveContext ec)
10235 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10236 return Expr.CreateExpressionTree (ec);
10239 protected override Expression DoResolve (ResolveContext ec)
10241 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10242 Expr = Expr.Resolve (ec);
10247 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10250 eclass = Expr.eclass;
10255 public override void Emit (EmitContext ec)
10257 using (ec.With (EmitContext.Options.CheckedScope, true))
10261 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10263 using (ec.With (EmitContext.Options.CheckedScope, true))
10264 Expr.EmitBranchable (ec, target, on_true);
10267 public override void FlowAnalysis (FlowAnalysisContext fc)
10269 Expr.FlowAnalysis (fc);
10272 public override SLE.Expression MakeExpression (BuilderContext ctx)
10274 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10275 return Expr.MakeExpression (ctx);
10279 protected override void CloneTo (CloneContext clonectx, Expression t)
10281 CheckedExpr target = (CheckedExpr) t;
10283 target.Expr = Expr.Clone (clonectx);
10286 public override object Accept (StructuralVisitor visitor)
10288 return visitor.Visit (this);
10293 /// Implements the unchecked expression
10295 public class UnCheckedExpr : Expression {
10297 public Expression Expr;
10299 public UnCheckedExpr (Expression e, Location l)
10305 public override bool ContainsEmitWithAwait ()
10307 return Expr.ContainsEmitWithAwait ();
10310 public override Expression CreateExpressionTree (ResolveContext ec)
10312 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10313 return Expr.CreateExpressionTree (ec);
10316 protected override Expression DoResolve (ResolveContext ec)
10318 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10319 Expr = Expr.Resolve (ec);
10324 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10327 eclass = Expr.eclass;
10332 public override void Emit (EmitContext ec)
10334 using (ec.With (EmitContext.Options.CheckedScope, false))
10338 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10340 using (ec.With (EmitContext.Options.CheckedScope, false))
10341 Expr.EmitBranchable (ec, target, on_true);
10344 public override void FlowAnalysis (FlowAnalysisContext fc)
10346 Expr.FlowAnalysis (fc);
10349 protected override void CloneTo (CloneContext clonectx, Expression t)
10351 UnCheckedExpr target = (UnCheckedExpr) t;
10353 target.Expr = Expr.Clone (clonectx);
10356 public override object Accept (StructuralVisitor visitor)
10358 return visitor.Visit (this);
10363 /// An Element Access expression.
10365 /// During semantic analysis these are transformed into
10366 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10368 public class ElementAccess : Expression
10370 public Arguments Arguments;
10371 public Expression Expr;
10372 bool conditional_access_receiver;
10374 public ElementAccess (Expression e, Arguments args, Location loc)
10378 this.Arguments = args;
10381 public bool ConditionalAccess { get; set; }
10383 public override Location StartLocation {
10385 return Expr.StartLocation;
10389 public override bool ContainsEmitWithAwait ()
10391 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10395 // We perform some simple tests, and then to "split" the emit and store
10396 // code we create an instance of a different class, and return that.
10398 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10400 if (conditionalAccessReceiver)
10401 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10403 Expr = Expr.Resolve (ec);
10405 if (conditionalAccessReceiver)
10406 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10413 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10414 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10418 if (type.IsArray) {
10419 var aa = new ArrayAccess (this, loc) {
10420 ConditionalAccess = ConditionalAccess,
10423 if (conditionalAccessReceiver)
10424 aa.SetConditionalAccessReceiver ();
10429 if (type.IsPointer)
10430 return Expr.MakePointerAccess (ec, type, Arguments);
10432 FieldExpr fe = Expr as FieldExpr;
10434 var ff = fe.Spec as FixedFieldSpec;
10436 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10440 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10441 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10442 var indexer = new IndexerExpr (indexers, type, this) {
10443 ConditionalAccess = ConditionalAccess
10446 if (conditionalAccessReceiver)
10447 indexer.SetConditionalAccessReceiver ();
10452 Error_CannotApplyIndexing (ec, type, loc);
10457 public override Expression CreateExpressionTree (ResolveContext ec)
10459 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10460 Expr.CreateExpressionTree (ec));
10462 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10465 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10467 if (type != InternalType.ErrorType) {
10468 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10469 type.GetSignatureForError ());
10473 public override bool HasConditionalAccess ()
10475 return ConditionalAccess || Expr.HasConditionalAccess ();
10478 void ResolveConditionalAccessReceiver (ResolveContext rc)
10480 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10481 conditional_access_receiver = true;
10485 protected override Expression DoResolve (ResolveContext rc)
10487 ResolveConditionalAccessReceiver (rc);
10489 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10493 return expr.Resolve (rc);
10496 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10498 var res = CreateAccessExpression (ec, false);
10502 return res.ResolveLValue (ec, rhs);
10505 public override void Emit (EmitContext ec)
10507 throw new Exception ("Should never be reached");
10510 public override void FlowAnalysis (FlowAnalysisContext fc)
10512 Expr.FlowAnalysis (fc);
10514 Arguments.FlowAnalysis (fc);
10517 public override string GetSignatureForError ()
10519 return Expr.GetSignatureForError ();
10522 protected override void CloneTo (CloneContext clonectx, Expression t)
10524 ElementAccess target = (ElementAccess) t;
10526 target.Expr = Expr.Clone (clonectx);
10527 if (Arguments != null)
10528 target.Arguments = Arguments.Clone (clonectx);
10531 public override object Accept (StructuralVisitor visitor)
10533 return visitor.Visit (this);
10538 /// Implements array access
10540 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10542 // Points to our "data" repository
10546 LocalTemporary temp;
10548 bool? has_await_args;
10549 bool conditional_access_receiver;
10551 public ArrayAccess (ElementAccess ea_data, Location l)
10557 public bool ConditionalAccess { get; set; }
10559 public void AddressOf (EmitContext ec, AddressOp mode)
10561 var ac = (ArrayContainer) ea.Expr.Type;
10563 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10564 LoadInstanceAndArguments (ec, false, true);
10567 LoadInstanceAndArguments (ec, false, false);
10569 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10570 ec.Emit (OpCodes.Readonly);
10572 ec.EmitArrayAddress (ac);
10575 public override Expression CreateExpressionTree (ResolveContext ec)
10577 if (ConditionalAccess)
10578 Error_NullShortCircuitInsideExpressionTree (ec);
10580 return ea.CreateExpressionTree (ec);
10583 public override bool ContainsEmitWithAwait ()
10585 return ea.ContainsEmitWithAwait ();
10588 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10590 if (HasConditionalAccess ())
10591 Error_NullPropagatingLValue (ec);
10593 return DoResolve (ec);
10596 protected override Expression DoResolve (ResolveContext ec)
10598 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10600 ea.Arguments.Resolve (ec, out dynamic);
10602 var ac = ea.Expr.Type as ArrayContainer;
10603 int rank = ea.Arguments.Count;
10604 if (ac.Rank != rank) {
10605 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10606 rank.ToString (), ac.Rank.ToString ());
10611 if (type.IsPointer) {
10612 if (ec.CurrentIterator != null) {
10613 UnsafeInsideIteratorError (ec, ea.Location);
10614 } else if (!ec.IsUnsafe) {
10615 UnsafeError (ec, ea.Location);
10619 if (conditional_access_receiver)
10620 type = LiftMemberType (ec, type);
10622 foreach (Argument a in ea.Arguments) {
10623 var na = a as NamedArgument;
10625 ElementAccess.Error_NamedArgument (na, ec.Report);
10627 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10630 eclass = ExprClass.Variable;
10635 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10637 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10640 public override void FlowAnalysis (FlowAnalysisContext fc)
10642 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10644 ea.FlowAnalysis (fc);
10646 if (conditional_access_receiver)
10647 fc.DefiniteAssignment = da;
10650 public override bool HasConditionalAccess ()
10652 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10656 // Load the array arguments into the stack.
10658 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10660 if (prepareAwait) {
10661 ea.Expr = ea.Expr.EmitToField (ec);
10663 var ie = new InstanceEmitter (ea.Expr, false);
10664 ie.Emit (ec, ConditionalAccess);
10666 if (duplicateArguments) {
10667 ec.Emit (OpCodes.Dup);
10669 var copy = new LocalTemporary (ea.Expr.Type);
10675 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10676 if (dup_args != null)
10677 ea.Arguments = dup_args;
10680 public void Emit (EmitContext ec, bool leave_copy)
10683 ec.EmitLoadFromPtr (type);
10685 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10686 LoadInstanceAndArguments (ec, false, true);
10689 if (conditional_access_receiver)
10690 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10692 var ac = (ArrayContainer) ea.Expr.Type;
10693 LoadInstanceAndArguments (ec, false, false);
10694 ec.EmitArrayLoad (ac);
10696 if (conditional_access_receiver)
10697 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10701 ec.Emit (OpCodes.Dup);
10702 temp = new LocalTemporary (this.type);
10707 public override void Emit (EmitContext ec)
10712 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10714 var ac = (ArrayContainer) ea.Expr.Type;
10715 TypeSpec t = source.Type;
10717 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10720 // When we are dealing with a struct, get the address of it to avoid value copy
10721 // Same cannot be done for reference type because array covariance and the
10722 // check in ldelema requires to specify the type of array element stored at the index
10724 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10725 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10727 if (has_await_args.Value) {
10728 if (source.ContainsEmitWithAwait ()) {
10729 source = source.EmitToField (ec);
10730 isCompound = false;
10734 LoadInstanceAndArguments (ec, isCompound, false);
10739 ec.EmitArrayAddress (ac);
10742 ec.Emit (OpCodes.Dup);
10746 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10748 if (has_await_args.Value) {
10749 if (source.ContainsEmitWithAwait ())
10750 source = source.EmitToField (ec);
10752 LoadInstanceAndArguments (ec, false, false);
10759 var lt = ea.Expr as LocalTemporary;
10765 ec.Emit (OpCodes.Dup);
10766 temp = new LocalTemporary (this.type);
10771 ec.EmitStoreFromPtr (t);
10773 ec.EmitArrayStore (ac);
10776 if (temp != null) {
10782 public override Expression EmitToField (EmitContext ec)
10785 // Have to be specialized for arrays to get access to
10786 // underlying element. Instead of another result copy we
10787 // need direct access to element
10791 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10793 ea.Expr = ea.Expr.EmitToField (ec);
10794 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10798 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10800 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10803 public override SLE.Expression MakeExpression (BuilderContext ctx)
10805 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10808 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10810 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10811 return Arguments.MakeExpression (ea.Arguments, ctx);
10815 public void SetConditionalAccessReceiver ()
10817 conditional_access_receiver = true;
10822 // Indexer access expression
10824 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10826 IList<MemberSpec> indexers;
10827 Arguments arguments;
10828 TypeSpec queried_type;
10830 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10831 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10835 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10838 this.indexers = indexers;
10839 this.queried_type = queriedType;
10840 this.InstanceExpression = instance;
10841 this.arguments = args;
10846 protected override Arguments Arguments {
10855 protected override TypeSpec DeclaringType {
10857 return best_candidate.DeclaringType;
10861 public override bool IsInstance {
10867 public override bool IsStatic {
10873 public override string KindName {
10874 get { return "indexer"; }
10877 public override string Name {
10885 public override bool ContainsEmitWithAwait ()
10887 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10890 public override Expression CreateExpressionTree (ResolveContext ec)
10892 if (ConditionalAccess) {
10893 Error_NullShortCircuitInsideExpressionTree (ec);
10896 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10897 InstanceExpression.CreateExpressionTree (ec),
10898 new TypeOfMethod (Getter, loc));
10900 return CreateExpressionFactoryCall (ec, "Call", args);
10903 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10905 LocalTemporary await_source_arg = null;
10908 emitting_compound_assignment = true;
10909 if (source is DynamicExpressionStatement) {
10914 emitting_compound_assignment = false;
10916 if (has_await_arguments) {
10917 await_source_arg = new LocalTemporary (Type);
10918 await_source_arg.Store (ec);
10920 arguments.Add (new Argument (await_source_arg));
10923 temp = await_source_arg;
10926 has_await_arguments = false;
10931 ec.Emit (OpCodes.Dup);
10932 temp = new LocalTemporary (Type);
10938 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10939 source = source.EmitToField (ec);
10941 temp = new LocalTemporary (Type);
10948 arguments.Add (new Argument (source));
10951 var call = new CallEmitter ();
10952 call.InstanceExpression = InstanceExpression;
10953 if (arguments == null)
10954 call.InstanceExpressionOnStack = true;
10956 call.Emit (ec, Setter, arguments, loc);
10958 if (temp != null) {
10961 } else if (leave_copy) {
10965 if (await_source_arg != null) {
10966 await_source_arg.Release (ec);
10970 public override void FlowAnalysis (FlowAnalysisContext fc)
10972 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10974 base.FlowAnalysis (fc);
10975 arguments.FlowAnalysis (fc);
10977 if (conditional_access_receiver)
10978 fc.DefiniteAssignment = da;
10981 public override string GetSignatureForError ()
10983 return best_candidate.GetSignatureForError ();
10986 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10989 throw new NotSupportedException ();
10991 var value = new[] { source.MakeExpression (ctx) };
10992 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10993 return SLE.Expression.Block (
10994 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10999 public override SLE.Expression MakeExpression (BuilderContext ctx)
11002 return base.MakeExpression (ctx);
11004 var args = Arguments.MakeExpression (arguments, ctx);
11005 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
11009 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
11011 if (best_candidate != null)
11014 eclass = ExprClass.IndexerAccess;
11017 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
11018 arguments.Resolve (rc, out dynamic);
11021 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11024 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
11025 res.BaseMembersProvider = this;
11026 res.InstanceQualifier = this;
11028 // TODO: Do I need 2 argument sets?
11029 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
11030 if (best_candidate != null)
11031 type = res.BestCandidateReturnType;
11032 else if (!res.BestCandidateIsDynamic)
11037 // It has dynamic arguments
11040 Arguments args = new Arguments (arguments.Count + 1);
11042 rc.Report.Error (1972, loc,
11043 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
11045 args.Add (new Argument (InstanceExpression));
11047 args.AddRange (arguments);
11049 best_candidate = null;
11050 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11054 // Try to avoid resolving left expression again
11056 if (right_side != null)
11057 ResolveInstanceExpression (rc, right_side);
11062 protected override void CloneTo (CloneContext clonectx, Expression t)
11064 IndexerExpr target = (IndexerExpr) t;
11066 if (arguments != null)
11067 target.arguments = arguments.Clone (clonectx);
11070 public void SetConditionalAccessReceiver ()
11072 conditional_access_receiver = true;
11075 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11077 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11080 #region IBaseMembersProvider Members
11082 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11084 var baseType = type.BaseType;
11085 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11087 if (members == null && !type.IsInterface) {
11088 var tps = queried_type as TypeParameterSpec;
11090 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11096 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11098 if (queried_type == member.DeclaringType)
11101 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11102 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11105 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11114 // A base access expression
11116 public class BaseThis : This
11118 public BaseThis (Location loc)
11123 public BaseThis (TypeSpec type, Location loc)
11127 eclass = ExprClass.Variable;
11132 public override string Name {
11140 public override Expression CreateExpressionTree (ResolveContext ec)
11142 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11143 return base.CreateExpressionTree (ec);
11146 public override void Emit (EmitContext ec)
11150 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11151 var context_type = ec.CurrentType;
11152 ec.Emit (OpCodes.Ldobj, context_type);
11153 ec.Emit (OpCodes.Box, context_type);
11157 protected override void Error_ThisNotAvailable (ResolveContext ec)
11160 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11162 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11166 public override void ResolveBase (ResolveContext ec)
11168 base.ResolveBase (ec);
11169 type = ec.CurrentType.BaseType;
11172 public override object Accept (StructuralVisitor visitor)
11174 return visitor.Visit (this);
11179 /// This class exists solely to pass the Type around and to be a dummy
11180 /// that can be passed to the conversion functions (this is used by
11181 /// foreach implementation to typecast the object return value from
11182 /// get_Current into the proper type. All code has been generated and
11183 /// we only care about the side effect conversions to be performed
11185 /// This is also now used as a placeholder where a no-action expression
11186 /// is needed (the `New' class).
11188 public class EmptyExpression : Expression
11190 sealed class OutAccessExpression : EmptyExpression
11192 public OutAccessExpression (TypeSpec t)
11197 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11199 rc.Report.Error (206, right_side.Location,
11200 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11206 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11207 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11208 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11209 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11210 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11211 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11212 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11213 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11215 public EmptyExpression (TypeSpec t)
11218 eclass = ExprClass.Value;
11219 loc = Location.Null;
11222 protected override void CloneTo (CloneContext clonectx, Expression target)
11226 public override bool ContainsEmitWithAwait ()
11231 public override Expression CreateExpressionTree (ResolveContext ec)
11233 throw new NotSupportedException ("ET");
11236 protected override Expression DoResolve (ResolveContext ec)
11241 public override void Emit (EmitContext ec)
11243 // nothing, as we only exist to not do anything.
11246 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11250 public override void EmitSideEffect (EmitContext ec)
11254 public override object Accept (StructuralVisitor visitor)
11256 return visitor.Visit (this);
11260 sealed class EmptyAwaitExpression : EmptyExpression
11262 public EmptyAwaitExpression (TypeSpec type)
11267 public override bool ContainsEmitWithAwait ()
11274 // Empty statement expression
11276 public sealed class EmptyExpressionStatement : ExpressionStatement
11278 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11280 private EmptyExpressionStatement ()
11282 loc = Location.Null;
11285 public override bool ContainsEmitWithAwait ()
11290 public override Expression CreateExpressionTree (ResolveContext ec)
11295 public override void EmitStatement (EmitContext ec)
11300 protected override Expression DoResolve (ResolveContext ec)
11302 eclass = ExprClass.Value;
11303 type = ec.BuiltinTypes.Object;
11307 public override void Emit (EmitContext ec)
11312 public override object Accept (StructuralVisitor visitor)
11314 return visitor.Visit (this);
11318 public class ErrorExpression : EmptyExpression
11320 public static readonly ErrorExpression Instance = new ErrorExpression ();
11322 private ErrorExpression ()
11323 : base (InternalType.ErrorType)
11327 public override Expression CreateExpressionTree (ResolveContext ec)
11332 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11337 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11341 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11345 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11349 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11353 public override object Accept (StructuralVisitor visitor)
11355 return visitor.Visit (this);
11359 public class UserCast : Expression {
11363 public UserCast (MethodSpec method, Expression source, Location l)
11365 if (source == null)
11366 throw new ArgumentNullException ("source");
11368 this.method = method;
11369 this.source = source;
11370 type = method.ReturnType;
11374 public Expression Source {
11383 public override bool ContainsEmitWithAwait ()
11385 return source.ContainsEmitWithAwait ();
11388 public override Expression CreateExpressionTree (ResolveContext ec)
11390 Arguments args = new Arguments (3);
11391 args.Add (new Argument (source.CreateExpressionTree (ec)));
11392 args.Add (new Argument (new TypeOf (type, loc)));
11393 args.Add (new Argument (new TypeOfMethod (method, loc)));
11394 return CreateExpressionFactoryCall (ec, "Convert", args);
11397 protected override Expression DoResolve (ResolveContext ec)
11399 method.CheckObsoleteness (ec, source.Location);
11401 eclass = ExprClass.Value;
11405 public override void Emit (EmitContext ec)
11408 ec.MarkCallEntry (loc);
11409 ec.Emit (OpCodes.Call, method);
11412 public override void FlowAnalysis (FlowAnalysisContext fc)
11414 source.FlowAnalysis (fc);
11417 public override string GetSignatureForError ()
11419 return TypeManager.CSharpSignature (method);
11422 public override SLE.Expression MakeExpression (BuilderContext ctx)
11425 return base.MakeExpression (ctx);
11427 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11433 // Holds additional type specifiers like ?, *, []
11435 public class ComposedTypeSpecifier
11437 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11439 public readonly int Dimension;
11440 public readonly Location Location;
11442 public ComposedTypeSpecifier (int specifier, Location loc)
11444 this.Dimension = specifier;
11445 this.Location = loc;
11449 public bool IsNullable {
11451 return Dimension == -1;
11455 public bool IsPointer {
11457 return Dimension == -2;
11461 public ComposedTypeSpecifier Next { get; set; }
11465 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11467 return new ComposedTypeSpecifier (dimension, loc);
11470 public static ComposedTypeSpecifier CreateNullable (Location loc)
11472 return new ComposedTypeSpecifier (-1, loc);
11475 public static ComposedTypeSpecifier CreatePointer (Location loc)
11477 return new ComposedTypeSpecifier (-2, loc);
11480 public string GetSignatureForError ()
11485 ArrayContainer.GetPostfixSignature (Dimension);
11487 return Next != null ? s + Next.GetSignatureForError () : s;
11492 // This class is used to "construct" the type during a typecast
11493 // operation. Since the Type.GetType class in .NET can parse
11494 // the type specification, we just use this to construct the type
11495 // one bit at a time.
11497 public class ComposedCast : TypeExpr {
11498 FullNamedExpression left;
11499 ComposedTypeSpecifier spec;
11501 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11504 throw new ArgumentNullException ("spec");
11508 this.loc = left.Location;
11511 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11513 type = left.ResolveAsType (ec);
11517 eclass = ExprClass.Type;
11519 var single_spec = spec;
11521 if (single_spec.IsNullable) {
11522 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11526 single_spec = single_spec.Next;
11527 } else if (single_spec.IsPointer) {
11529 // Declared fields cannot have unmanaged check done before all types are defined
11531 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11534 var rc = ec as ResolveContext;
11535 if (rc?.CurrentIterator != null) {
11536 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11537 } else if (!ec.IsUnsafe) {
11538 UnsafeError (ec.Module.Compiler.Report, loc);
11542 type = PointerContainer.MakeType (ec.Module, type);
11543 single_spec = single_spec.Next;
11544 } while (single_spec != null && single_spec.IsPointer);
11547 if (single_spec != null && single_spec.Dimension > 0) {
11548 if (type.IsSpecialRuntimeType) {
11549 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11550 } else if (type.IsStatic) {
11551 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11552 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11553 type.GetSignatureForError ());
11555 MakeArray (ec.Module, single_spec);
11562 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11564 if (spec.Next != null)
11565 MakeArray (module, spec.Next);
11567 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11570 public override string GetSignatureForError ()
11572 return left.GetSignatureForError () + spec.GetSignatureForError ();
11575 public override object Accept (StructuralVisitor visitor)
11577 return visitor.Visit (this);
11581 class FixedBufferPtr : Expression
11583 readonly Expression array;
11585 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11587 this.type = array_type;
11588 this.array = array;
11592 public override bool ContainsEmitWithAwait ()
11594 throw new NotImplementedException ();
11597 public override Expression CreateExpressionTree (ResolveContext ec)
11599 Error_PointerInsideExpressionTree (ec);
11603 public override void Emit(EmitContext ec)
11608 protected override Expression DoResolve (ResolveContext ec)
11610 type = PointerContainer.MakeType (ec.Module, type);
11611 eclass = ExprClass.Value;
11618 // This class is used to represent the address of an array, used
11619 // only by the Fixed statement, this generates "&a [0]" construct
11620 // for fixed (char *pa = a)
11622 class ArrayPtr : FixedBufferPtr
11624 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11625 base (array, array_type, l)
11629 public override void Emit (EmitContext ec)
11634 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11639 // Encapsulates a conversion rules required for array indexes
11641 public class ArrayIndexCast : TypeCast
11643 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11644 : base (expr, returnType)
11646 if (expr.Type == returnType) // int -> int
11647 throw new ArgumentException ("unnecessary array index conversion");
11650 public override Expression CreateExpressionTree (ResolveContext ec)
11652 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11653 return base.CreateExpressionTree (ec);
11657 public override void Emit (EmitContext ec)
11661 switch (child.Type.BuiltinType) {
11662 case BuiltinTypeSpec.Type.UInt:
11663 ec.Emit (OpCodes.Conv_U);
11665 case BuiltinTypeSpec.Type.Long:
11666 ec.Emit (OpCodes.Conv_Ovf_I);
11668 case BuiltinTypeSpec.Type.ULong:
11669 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11672 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11678 // Implements the `stackalloc' keyword
11680 public class StackAlloc : Expression {
11685 public StackAlloc (Expression type, Expression count, Location l)
11688 this.count = count;
11692 public Expression TypeExpression {
11698 public Expression CountExpression {
11704 public override bool ContainsEmitWithAwait ()
11709 public override Expression CreateExpressionTree (ResolveContext ec)
11711 throw new NotSupportedException ("ET");
11714 protected override Expression DoResolve (ResolveContext ec)
11716 count = count.Resolve (ec);
11720 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11721 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11726 Constant c = count as Constant;
11727 if (c != null && c.IsNegative) {
11728 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11731 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11732 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11735 otype = texpr.ResolveAsType (ec);
11739 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11742 type = PointerContainer.MakeType (ec.Module, otype);
11743 eclass = ExprClass.Value;
11748 public override void Emit (EmitContext ec)
11750 int size = BuiltinTypeSpec.GetSize (otype);
11755 ec.Emit (OpCodes.Sizeof, otype);
11759 ec.Emit (OpCodes.Mul_Ovf_Un);
11760 ec.Emit (OpCodes.Localloc);
11763 protected override void CloneTo (CloneContext clonectx, Expression t)
11765 StackAlloc target = (StackAlloc) t;
11766 target.count = count.Clone (clonectx);
11767 target.texpr = texpr.Clone (clonectx);
11770 public override object Accept (StructuralVisitor visitor)
11772 return visitor.Visit (this);
11777 // An object initializer expression
11779 public class ElementInitializer : Assign
11781 public readonly string Name;
11783 public ElementInitializer (string name, Expression initializer, Location loc)
11784 : base (null, initializer, loc)
11789 public bool IsDictionaryInitializer {
11791 return Name == null;
11795 protected override void CloneTo (CloneContext clonectx, Expression t)
11797 ElementInitializer target = (ElementInitializer) t;
11798 target.source = source.Clone (clonectx);
11801 public override Expression CreateExpressionTree (ResolveContext ec)
11803 Arguments args = new Arguments (2);
11804 FieldExpr fe = target as FieldExpr;
11806 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11808 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11811 Expression arg_expr;
11812 var cinit = source as CollectionOrObjectInitializers;
11813 if (cinit == null) {
11815 arg_expr = source.CreateExpressionTree (ec);
11817 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11818 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11821 args.Add (new Argument (arg_expr));
11822 return CreateExpressionFactoryCall (ec, mname, args);
11825 protected override Expression DoResolve (ResolveContext ec)
11827 if (source == null)
11828 return EmptyExpressionStatement.Instance;
11830 if (!ResolveElement (ec))
11833 if (source is CollectionOrObjectInitializers) {
11834 target = target.Resolve (ec);
11835 if (target == null)
11838 Expression previous = ec.CurrentInitializerVariable;
11839 ec.CurrentInitializerVariable = target;
11840 source = source.Resolve (ec);
11841 ec.CurrentInitializerVariable = previous;
11842 if (source == null)
11845 eclass = source.eclass;
11846 type = source.Type;
11851 return base.DoResolve (ec);
11854 public override void EmitStatement (EmitContext ec)
11856 if (source is CollectionOrObjectInitializers)
11859 base.EmitStatement (ec);
11862 protected virtual bool ResolveElement (ResolveContext rc)
11864 var t = rc.CurrentInitializerVariable.Type;
11865 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11866 Arguments args = new Arguments (1);
11867 args.Add (new Argument (rc.CurrentInitializerVariable));
11868 target = new DynamicMemberBinder (Name, args, loc);
11870 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11871 if (member == null) {
11872 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11874 if (member != null) {
11875 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11876 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11881 if (member == null) {
11882 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11886 var me = member as MemberExpr;
11887 if (me is EventExpr) {
11888 me = me.ResolveMemberAccess (rc, null, null);
11889 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11890 rc.Report.Error (1913, loc,
11891 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11892 member.GetSignatureForError ());
11898 rc.Report.Error (1914, loc,
11899 "Static field or property `{0}' cannot be assigned in an object initializer",
11900 me.GetSignatureForError ());
11904 me.InstanceExpression = rc.CurrentInitializerVariable;
11912 // A collection initializer expression
11914 class CollectionElementInitializer : Invocation
11916 public class ElementInitializerArgument : Argument
11918 public ElementInitializerArgument (Expression e)
11924 sealed class AddMemberAccess : MemberAccess
11926 public AddMemberAccess (Expression expr, Location loc)
11927 : base (expr, "Add", loc)
11931 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11933 if (TypeManager.HasElementType (type))
11936 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11940 public CollectionElementInitializer (Expression argument)
11941 : base (null, new Arguments (1))
11943 base.arguments.Add (new ElementInitializerArgument (argument));
11944 this.loc = argument.Location;
11947 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11948 : base (null, new Arguments (arguments.Count))
11950 foreach (Expression e in arguments)
11951 base.arguments.Add (new ElementInitializerArgument (e));
11956 public CollectionElementInitializer (Location loc)
11957 : base (null, null)
11962 public override Expression CreateExpressionTree (ResolveContext ec)
11964 Arguments args = new Arguments (2);
11965 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11967 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11968 foreach (Argument a in arguments) {
11969 if (a.ArgType == Argument.AType.ExtensionType) {
11970 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11973 expr_initializers.Add (a.CreateExpressionTree (ec));
11976 args.Add (new Argument (new ArrayCreation (
11977 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11978 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11981 protected override void CloneTo (CloneContext clonectx, Expression t)
11983 CollectionElementInitializer target = (CollectionElementInitializer) t;
11984 if (arguments != null)
11985 target.arguments = arguments.Clone (clonectx);
11988 protected override Expression DoResolve (ResolveContext ec)
11990 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11992 return base.DoResolve (ec);
11996 class DictionaryElementInitializer : ElementInitializer
11998 readonly Arguments args;
12000 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
12001 : base (null, initializer, loc)
12003 this.args = arguments;
12006 public override Expression CreateExpressionTree (ResolveContext ec)
12008 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
12012 protected override bool ResolveElement (ResolveContext rc)
12014 var init = rc.CurrentInitializerVariable;
12015 var type = init.Type;
12017 if (type.IsArray) {
12018 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
12022 if (type.IsPointer) {
12023 target = init.MakePointerAccess (rc, type, args);
12027 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
12028 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12029 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
12033 target = new IndexerExpr (indexers, type, init, args, loc);
12039 // A block of object or collection initializers
12041 public class CollectionOrObjectInitializers : ExpressionStatement
12043 IList<Expression> initializers;
12044 bool is_collection_initialization;
12046 public CollectionOrObjectInitializers (Location loc)
12047 : this (new Expression[0], loc)
12051 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12053 this.initializers = initializers;
12057 public IList<Expression> Initializers {
12059 return initializers;
12063 public bool IsEmpty {
12065 return initializers.Count == 0;
12069 public bool IsCollectionInitializer {
12071 return is_collection_initialization;
12075 protected override void CloneTo (CloneContext clonectx, Expression target)
12077 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12079 t.initializers = new List<Expression> (initializers.Count);
12080 foreach (var e in initializers)
12081 t.initializers.Add (e.Clone (clonectx));
12084 public override bool ContainsEmitWithAwait ()
12086 foreach (var e in initializers) {
12087 if (e.ContainsEmitWithAwait ())
12094 public override Expression CreateExpressionTree (ResolveContext ec)
12096 return CreateExpressionTree (ec, false);
12099 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12101 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12102 foreach (Expression e in initializers) {
12103 Expression expr = e.CreateExpressionTree (ec);
12105 expr_initializers.Add (expr);
12109 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12111 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12114 protected override Expression DoResolve (ResolveContext ec)
12116 List<string> element_names = null;
12117 for (int i = 0; i < initializers.Count; ++i) {
12118 Expression initializer = initializers [i];
12119 ElementInitializer element_initializer = initializer as ElementInitializer;
12122 if (element_initializer != null) {
12123 element_names = new List<string> (initializers.Count);
12124 if (!element_initializer.IsDictionaryInitializer)
12125 element_names.Add (element_initializer.Name);
12126 } else if (initializer is CompletingExpression) {
12127 initializer.Resolve (ec);
12128 throw new InternalErrorException ("This line should never be reached");
12130 var t = ec.CurrentInitializerVariable.Type;
12131 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12132 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12133 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12134 "object initializer because type `{1}' does not implement `{2}' interface",
12135 ec.CurrentInitializerVariable.GetSignatureForError (),
12136 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12137 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12140 is_collection_initialization = true;
12143 if (is_collection_initialization != (element_initializer == null)) {
12144 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12145 is_collection_initialization ? "collection initializer" : "object initializer");
12149 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12150 if (element_names.Contains (element_initializer.Name)) {
12151 ec.Report.Error (1912, element_initializer.Location,
12152 "An object initializer includes more than one member `{0}' initialization",
12153 element_initializer.Name);
12155 element_names.Add (element_initializer.Name);
12160 Expression e = initializer.Resolve (ec);
12161 if (e == EmptyExpressionStatement.Instance)
12162 initializers.RemoveAt (i--);
12164 initializers [i] = e;
12167 type = ec.CurrentInitializerVariable.Type;
12168 if (is_collection_initialization) {
12169 if (TypeManager.HasElementType (type)) {
12170 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12171 type.GetSignatureForError ());
12175 eclass = ExprClass.Variable;
12179 public override void Emit (EmitContext ec)
12181 EmitStatement (ec);
12184 public override void EmitStatement (EmitContext ec)
12186 foreach (ExpressionStatement e in initializers) {
12187 // TODO: need location region
12188 ec.Mark (e.Location);
12189 e.EmitStatement (ec);
12193 public override void FlowAnalysis (FlowAnalysisContext fc)
12195 foreach (var initializer in initializers) {
12196 if (initializer != null)
12197 initializer.FlowAnalysis (fc);
12203 // New expression with element/object initializers
12205 public class NewInitialize : New
12208 // This class serves as a proxy for variable initializer target instances.
12209 // A real variable is assigned later when we resolve left side of an
12212 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12214 NewInitialize new_instance;
12216 public InitializerTargetExpression (NewInitialize newInstance)
12218 this.type = newInstance.type;
12219 this.loc = newInstance.loc;
12220 this.eclass = newInstance.eclass;
12221 this.new_instance = newInstance;
12224 public override bool ContainsEmitWithAwait ()
12229 public override Expression CreateExpressionTree (ResolveContext ec)
12231 // Should not be reached
12232 throw new NotSupportedException ("ET");
12235 protected override Expression DoResolve (ResolveContext ec)
12240 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12245 public override void Emit (EmitContext ec)
12247 Expression e = (Expression) new_instance.instance;
12251 public override Expression EmitToField (EmitContext ec)
12253 return (Expression) new_instance.instance;
12256 #region IMemoryLocation Members
12258 public void AddressOf (EmitContext ec, AddressOp mode)
12260 new_instance.instance.AddressOf (ec, mode);
12266 CollectionOrObjectInitializers initializers;
12267 IMemoryLocation instance;
12268 DynamicExpressionStatement dynamic;
12270 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12271 : base (requested_type, arguments, l)
12273 this.initializers = initializers;
12276 public CollectionOrObjectInitializers Initializers {
12278 return initializers;
12282 protected override void CloneTo (CloneContext clonectx, Expression t)
12284 base.CloneTo (clonectx, t);
12286 NewInitialize target = (NewInitialize) t;
12287 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12290 public override bool ContainsEmitWithAwait ()
12292 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12295 public override Expression CreateExpressionTree (ResolveContext ec)
12297 Arguments args = new Arguments (2);
12298 args.Add (new Argument (base.CreateExpressionTree (ec)));
12299 if (!initializers.IsEmpty)
12300 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12302 return CreateExpressionFactoryCall (ec,
12303 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12307 protected override Expression DoResolve (ResolveContext rc)
12309 Expression e = base.DoResolve (rc);
12313 if (type.IsDelegate) {
12314 rc.Report.Error (1958, Initializers.Location,
12315 "Object and collection initializers cannot be used to instantiate a delegate");
12318 Expression previous = rc.CurrentInitializerVariable;
12319 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12320 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12321 initializers.Resolve (rc);
12323 rc.CurrentInitializerVariable = previous;
12325 dynamic = e as DynamicExpressionStatement;
12326 if (dynamic != null)
12332 public override void Emit (EmitContext ec)
12334 if (!CanEmitOptimizedLocalTarget (ec)) {
12335 var fe = ec.GetTemporaryField (type);
12337 if (!Emit (ec, fe))
12346 public override bool Emit (EmitContext ec, IMemoryLocation target)
12349 // Expression is initialized into temporary target then moved
12350 // to real one for atomicity
12352 IMemoryLocation temp_target = target;
12354 LocalTemporary temp = null;
12355 bool by_ref = false;
12356 if (!initializers.IsEmpty) {
12357 temp_target = target as LocalTemporary;
12358 if (temp_target == null)
12359 temp_target = target as StackFieldExpr;
12361 if (temp_target == null) {
12362 var vr = target as VariableReference;
12363 if (vr != null && vr.IsRef) {
12369 if (temp_target == null)
12370 temp_target = temp = new LocalTemporary (type);
12373 bool left_on_stack;
12374 if (dynamic != null) {
12376 left_on_stack = true;
12378 left_on_stack = base.Emit (ec, temp_target);
12381 if (initializers.IsEmpty)
12382 return left_on_stack;
12384 StackFieldExpr sf = null;
12386 // Move a new instance (reference-type) to local temporary variable
12387 if (left_on_stack) {
12389 temp_target = temp = new LocalTemporary (type);
12395 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12397 throw new NotImplementedException ();
12399 sf = ec.GetTemporaryField (type);
12400 sf.AutomaticallyReuse = false;
12401 sf.EmitAssign (ec, temp, false, false);
12404 left_on_stack = false;
12408 instance = temp_target;
12410 initializers.Emit (ec);
12412 ((Expression)temp_target).Emit (ec);
12418 sf.PrepareCleanup (ec);
12423 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12425 return !(method == null && TypeSpec.IsValueType (type) &&
12426 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12427 initializers.ContainsEmitWithAwait ());
12430 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12432 instance = base.EmitAddressOf (ec, Mode);
12434 if (!initializers.IsEmpty)
12435 initializers.Emit (ec);
12440 public override void FlowAnalysis (FlowAnalysisContext fc)
12442 base.FlowAnalysis (fc);
12443 initializers.FlowAnalysis (fc);
12446 public override object Accept (StructuralVisitor visitor)
12448 return visitor.Visit (this);
12452 public class NewAnonymousType : New
12454 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12456 List<AnonymousTypeParameter> parameters;
12457 readonly TypeContainer parent;
12458 AnonymousTypeClass anonymous_type;
12460 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12461 : base (null, null, loc)
12463 this.parameters = parameters;
12464 this.parent = parent;
12467 public List<AnonymousTypeParameter> Parameters {
12469 return this.parameters;
12473 protected override void CloneTo (CloneContext clonectx, Expression target)
12475 if (parameters == null)
12478 NewAnonymousType t = (NewAnonymousType) target;
12479 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12480 foreach (AnonymousTypeParameter atp in parameters)
12481 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12484 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12486 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12490 type = AnonymousTypeClass.Create (parent, parameters, loc);
12494 int errors = ec.Report.Errors;
12495 type.CreateContainer ();
12496 type.DefineContainer ();
12497 type.ExpandBaseInterfaces ();
12499 if ((ec.Report.Errors - errors) == 0) {
12500 parent.Module.AddAnonymousType (type);
12501 type.PrepareEmit ();
12507 public override Expression CreateExpressionTree (ResolveContext ec)
12509 if (parameters == null)
12510 return base.CreateExpressionTree (ec);
12512 var init = new ArrayInitializer (parameters.Count, loc);
12513 foreach (var m in anonymous_type.Members) {
12514 var p = m as Property;
12516 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12519 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12520 foreach (Argument a in arguments)
12521 ctor_args.Add (a.CreateExpressionTree (ec));
12523 Arguments args = new Arguments (3);
12524 args.Add (new Argument (new TypeOfMethod (method, loc)));
12525 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12526 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12528 return CreateExpressionFactoryCall (ec, "New", args);
12531 protected override Expression DoResolve (ResolveContext ec)
12533 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12534 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12538 if (parameters == null) {
12539 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12540 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12541 return base.DoResolve (ec);
12544 bool error = false;
12545 arguments = new Arguments (parameters.Count);
12546 var t_args = new TypeSpec [parameters.Count];
12547 for (int i = 0; i < parameters.Count; ++i) {
12548 Expression e = parameters [i].Resolve (ec);
12554 arguments.Add (new Argument (e));
12555 t_args [i] = e.Type;
12561 anonymous_type = CreateAnonymousType (ec, parameters);
12562 if (anonymous_type == null)
12565 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12566 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12567 eclass = ExprClass.Value;
12571 public override object Accept (StructuralVisitor visitor)
12573 return visitor.Visit (this);
12577 public class AnonymousTypeParameter : ShimExpression
12579 public readonly string Name;
12581 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12582 : base (initializer)
12588 public AnonymousTypeParameter (Parameter parameter)
12589 : base (new SimpleName (parameter.Name, parameter.Location))
12591 this.Name = parameter.Name;
12592 this.loc = parameter.Location;
12595 public override bool Equals (object o)
12597 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12598 return other != null && Name == other.Name;
12601 public override int GetHashCode ()
12603 return Name.GetHashCode ();
12606 protected override Expression DoResolve (ResolveContext ec)
12608 Expression e = expr.Resolve (ec);
12612 if (e.eclass == ExprClass.MethodGroup) {
12613 Error_InvalidInitializer (ec, e.ExprClassName);
12618 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
12619 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12626 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12628 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12629 Name, initializer);
12633 public class CatchFilterExpression : BooleanExpression
12635 public CatchFilterExpression (Expression expr, Location loc)
12642 public class InterpolatedString : Expression
12644 readonly StringLiteral start, end;
12645 List<Expression> interpolations;
12646 Arguments arguments;
12648 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12650 this.start = start;
12652 this.interpolations = interpolations;
12653 loc = start.Location;
12656 protected override void CloneTo (CloneContext clonectx, Expression t)
12658 InterpolatedString target = (InterpolatedString) t;
12660 if (interpolations != null) {
12661 target.interpolations = new List<Expression> ();
12662 foreach (var interpolation in interpolations) {
12663 target.interpolations.Add (interpolation.Clone (clonectx));
12668 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12670 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12671 if (factory == null)
12674 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12675 var res = new Invocation (ma, arguments).Resolve (rc);
12676 if (res != null && res.Type != type)
12677 res = Convert.ExplicitConversion (rc, res, type, loc);
12682 public override bool ContainsEmitWithAwait ()
12684 if (interpolations == null)
12687 foreach (var expr in interpolations) {
12688 if (expr.ContainsEmitWithAwait ())
12695 public override Expression CreateExpressionTree (ResolveContext rc)
12697 var best = ResolveBestFormatOverload (rc);
12701 Expression instance = new NullLiteral (loc);
12702 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12703 return CreateExpressionFactoryCall (rc, "Call", args);
12706 protected override Expression DoResolve (ResolveContext rc)
12710 if (interpolations == null) {
12712 arguments = new Arguments (1);
12714 arguments = new Arguments (interpolations.Count);
12716 var sb = new StringBuilder (start.Value);
12717 for (int i = 0; i < interpolations.Count; ++i) {
12719 sb.Append ('{').Append (i / 2);
12720 var isi = (InterpolatedStringInsert)interpolations [i];
12721 if (isi.Alignment != null) {
12723 var value = isi.ResolveAligment (rc);
12725 sb.Append (value.Value);
12728 if (isi.Format != null) {
12730 sb.Append (isi.Format);
12734 arguments.Add (new Argument (isi.Resolve (rc)));
12736 sb.Append (((StringLiteral)interpolations [i]).Value);
12740 sb.Append (end.Value);
12741 str = sb.ToString ();
12744 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12746 eclass = ExprClass.Value;
12747 type = rc.BuiltinTypes.String;
12751 public override void Emit (EmitContext ec)
12753 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12754 if (interpolations == null) {
12755 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12756 if (str != start.Value)
12757 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12764 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12768 var ca = new CallEmitter ();
12769 ca.Emit (ec, best, arguments, loc);
12772 public override void FlowAnalysis (FlowAnalysisContext fc)
12774 if (interpolations != null) {
12775 foreach (var expr in interpolations) {
12776 expr.FlowAnalysis (fc);
12781 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12783 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12784 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12785 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12789 public class InterpolatedStringInsert : CompositeExpression
12791 public InterpolatedStringInsert (Expression expr)
12796 public Expression Alignment { get; set; }
12797 public string Format { get; set; }
12799 protected override void CloneTo (CloneContext clonectx, Expression t)
12801 var target = (InterpolatedStringInsert)t;
12802 target.expr = expr.Clone (clonectx);
12803 if (Alignment != null)
12804 target.Alignment = Alignment.Clone (clonectx);
12807 protected override Expression DoResolve (ResolveContext rc)
12809 var expr = base.DoResolve (rc);
12814 // For better error reporting, assumes the built-in implementation uses object
12817 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12820 public override void FlowAnalysis (FlowAnalysisContext fc)
12822 Child.FlowAnalysis (fc);
12825 public int? ResolveAligment (ResolveContext rc)
12827 var c = Alignment.ResolveLabelConstant (rc);
12831 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12835 var value = (int) c.GetValueAsLong ();
12836 if (value > 32767 || value < -32767) {
12837 rc.Report.Warning (8094, 1, Alignment.Location,
12838 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12845 class ThrowExpression : ExpressionStatement
12849 public ThrowExpression (Expression expr, Location loc)
12855 protected override void CloneTo (CloneContext clonectx, Expression t)
12857 var target = (ThrowExpression)t;
12858 target.expr = expr.Clone (clonectx);
12861 public override bool ContainsEmitWithAwait ()
12863 return expr.ContainsEmitWithAwait ();
12866 public override Expression CreateExpressionTree (ResolveContext rc)
12868 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12872 protected override Expression DoResolve (ResolveContext rc)
12874 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12879 expr = Throw.ConvertType (rc, expr);
12881 eclass = ExprClass.Value;
12882 type = InternalType.ThrowExpr;
12886 public override void Emit (EmitContext ec)
12888 EmitStatement (ec);
12891 public override void EmitStatement (EmitContext ec)
12895 ec.Emit (OpCodes.Throw);
12898 public override void FlowAnalysis (FlowAnalysisContext fc)
12900 expr.FlowAnalysis (fc);
12903 public override Reachability MarkReachable (Reachability rc)
12905 return Reachability.CreateUnreachable ();