2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
721 if (ec.CurrentIterator != null) {
722 UnsafeInsideIteratorError (ec, loc);
723 } else if (!ec.IsUnsafe) {
724 UnsafeError (ec, loc);
727 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
728 if (Expr == null || Expr.eclass != ExprClass.Variable) {
729 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
733 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
737 IVariableReference vr = Expr as IVariableReference;
740 is_fixed = vr.IsFixed;
741 vr.SetHasAddressTaken ();
743 if (vr.IsHoisted && ec.CurrentIterator == null) {
744 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
747 IFixedExpression fe = Expr as IFixedExpression;
748 is_fixed = fe != null && fe.IsFixed;
751 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
752 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
755 type = PointerContainer.MakeType (ec.Module, Expr.Type);
756 eclass = ExprClass.Value;
760 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
762 expr = DoNumericPromotion (rc, Oper, expr);
763 TypeSpec expr_type = expr.Type;
764 foreach (TypeSpec t in predefined) {
772 // Perform user-operator overload resolution
774 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
776 CSharp.Operator.OpType op_type;
778 case Operator.LogicalNot:
779 op_type = CSharp.Operator.OpType.LogicalNot; break;
780 case Operator.OnesComplement:
781 op_type = CSharp.Operator.OpType.OnesComplement; break;
782 case Operator.UnaryNegation:
783 op_type = CSharp.Operator.OpType.UnaryNegation; break;
784 case Operator.UnaryPlus:
785 op_type = CSharp.Operator.OpType.UnaryPlus; break;
787 throw new InternalErrorException (Oper.ToString ());
790 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
794 Arguments args = new Arguments (1);
795 args.Add (new Argument (expr));
797 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
798 var oper = res.ResolveOperator (ec, ref args);
803 Expr = args [0].Expr;
804 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
808 // Unary user type overload resolution
810 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
812 Expression best_expr = ResolveUserOperator (ec, expr);
813 if (best_expr != null)
816 foreach (TypeSpec t in predefined) {
817 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
818 if (oper_expr == null)
821 if (oper_expr == ErrorExpression.Instance)
825 // decimal type is predefined but has user-operators
827 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
828 oper_expr = ResolveUserType (ec, oper_expr, predefined);
830 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
832 if (oper_expr == null)
835 if (best_expr == null) {
836 best_expr = oper_expr;
840 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
842 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
843 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
845 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
852 best_expr = oper_expr;
855 if (best_expr == null)
859 // HACK: Decimal user-operator is included in standard operators
861 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
865 type = best_expr.Type;
869 protected override void CloneTo (CloneContext clonectx, Expression t)
871 Unary target = (Unary) t;
873 target.Expr = Expr.Clone (clonectx);
876 public override object Accept (StructuralVisitor visitor)
878 return visitor.Visit (this);
884 // Unary operators are turned into Indirection expressions
885 // after semantic analysis (this is so we can take the address
886 // of an indirection).
888 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
890 LocalTemporary temporary;
893 public Indirection (Expression expr, Location l)
899 public Expression Expr {
905 public bool IsFixed {
909 public override Location StartLocation {
911 return expr.StartLocation;
915 protected override void CloneTo (CloneContext clonectx, Expression t)
917 Indirection target = (Indirection) t;
918 target.expr = expr.Clone (clonectx);
921 public override bool ContainsEmitWithAwait ()
923 throw new NotImplementedException ();
926 public override Expression CreateExpressionTree (ResolveContext ec)
928 Error_PointerInsideExpressionTree (ec);
932 public override void Emit (EmitContext ec)
937 ec.EmitLoadFromPtr (Type);
940 public void Emit (EmitContext ec, bool leave_copy)
944 ec.Emit (OpCodes.Dup);
945 temporary = new LocalTemporary (expr.Type);
946 temporary.Store (ec);
950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
952 prepared = isCompound;
957 ec.Emit (OpCodes.Dup);
961 ec.Emit (OpCodes.Dup);
962 temporary = new LocalTemporary (source.Type);
963 temporary.Store (ec);
966 ec.EmitStoreFromPtr (type);
968 if (temporary != null) {
970 temporary.Release (ec);
974 public void AddressOf (EmitContext ec, AddressOp Mode)
979 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
981 return DoResolve (ec);
984 protected override Expression DoResolve (ResolveContext ec)
986 expr = expr.Resolve (ec);
990 if (ec.CurrentIterator != null) {
991 UnsafeInsideIteratorError (ec, loc);
992 } else if (!ec.IsUnsafe) {
993 UnsafeError (ec, loc);
996 var pc = expr.Type as PointerContainer;
999 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1005 if (type.Kind == MemberKind.Void) {
1006 Error_VoidPointerOperation (ec);
1010 eclass = ExprClass.Variable;
1014 public override object Accept (StructuralVisitor visitor)
1016 return visitor.Visit (this);
1021 /// Unary Mutator expressions (pre and post ++ and --)
1025 /// UnaryMutator implements ++ and -- expressions. It derives from
1026 /// ExpressionStatement becuase the pre/post increment/decrement
1027 /// operators can be used in a statement context.
1029 /// FIXME: Idea, we could split this up in two classes, one simpler
1030 /// for the common case, and one with the extra fields for more complex
1031 /// classes (indexers require temporary access; overloaded require method)
1034 public class UnaryMutator : ExpressionStatement
1036 class DynamicPostMutator : Expression, IAssignMethod
1038 LocalTemporary temp;
1041 public DynamicPostMutator (Expression expr)
1044 this.type = expr.Type;
1045 this.loc = expr.Location;
1048 public override Expression CreateExpressionTree (ResolveContext ec)
1050 throw new NotImplementedException ("ET");
1053 protected override Expression DoResolve (ResolveContext rc)
1055 eclass = expr.eclass;
1059 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1061 expr.DoResolveLValue (ec, right_side);
1062 return DoResolve (ec);
1065 public override void Emit (EmitContext ec)
1070 public void Emit (EmitContext ec, bool leave_copy)
1072 throw new NotImplementedException ();
1076 // Emits target assignment using unmodified source value
1078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1081 // Allocate temporary variable to keep original value before it's modified
1083 temp = new LocalTemporary (type);
1087 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1098 public enum Mode : byte {
1105 PreDecrement = IsDecrement,
1106 PostIncrement = IsPost,
1107 PostDecrement = IsPost | IsDecrement
1111 bool is_expr, recurse;
1113 protected Expression expr;
1115 // Holds the real operation
1116 Expression operation;
1118 public UnaryMutator (Mode m, Expression e, Location loc)
1125 public Mode UnaryMutatorMode {
1131 public Expression Expr {
1137 public override Location StartLocation {
1139 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1143 public override bool ContainsEmitWithAwait ()
1145 return expr.ContainsEmitWithAwait ();
1148 public override Expression CreateExpressionTree (ResolveContext ec)
1150 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1153 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1156 // Predefined ++ and -- operators exist for the following types:
1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1159 return new TypeSpec[] {
1175 protected override Expression DoResolve (ResolveContext ec)
1177 expr = expr.Resolve (ec);
1179 if (expr == null || expr.Type == InternalType.ErrorType)
1182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 // Handle postfix unary operators using local
1185 // temporary variable
1187 if ((mode & Mode.IsPost) != 0)
1188 expr = new DynamicPostMutator (expr);
1190 Arguments args = new Arguments (1);
1191 args.Add (new Argument (expr));
1192 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1195 if (expr.Type.IsNullableType)
1196 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1198 return DoResolveOperation (ec);
1201 protected Expression DoResolveOperation (ResolveContext ec)
1203 eclass = ExprClass.Value;
1206 if (expr is RuntimeValueExpression) {
1209 // Use itself at the top of the stack
1210 operation = new EmptyExpression (type);
1214 // The operand of the prefix/postfix increment decrement operators
1215 // should be an expression that is classified as a variable,
1216 // a property access or an indexer access
1218 // TODO: Move to parser, expr is ATypeNameExpression
1219 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1220 expr = expr.ResolveLValue (ec, expr);
1222 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1226 // Step 1: Try to find a user operator, it has priority over predefined ones
1228 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1229 var methods = MemberCache.GetUserOperator (type, user_op, false);
1231 if (methods != null) {
1232 Arguments args = new Arguments (1);
1233 args.Add (new Argument (expr));
1235 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1236 var method = res.ResolveOperator (ec, ref args);
1240 args[0].Expr = operation;
1241 operation = new UserOperatorCall (method, args, null, loc);
1242 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1247 // Step 2: Try predefined types
1250 Expression source = null;
1251 bool primitive_type;
1254 // Predefined without user conversion first for speed-up
1256 // Predefined ++ and -- operators exist for the following types:
1257 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1259 switch (type.BuiltinType) {
1260 case BuiltinTypeSpec.Type.Byte:
1261 case BuiltinTypeSpec.Type.SByte:
1262 case BuiltinTypeSpec.Type.Short:
1263 case BuiltinTypeSpec.Type.UShort:
1264 case BuiltinTypeSpec.Type.Int:
1265 case BuiltinTypeSpec.Type.UInt:
1266 case BuiltinTypeSpec.Type.Long:
1267 case BuiltinTypeSpec.Type.ULong:
1268 case BuiltinTypeSpec.Type.Char:
1269 case BuiltinTypeSpec.Type.Float:
1270 case BuiltinTypeSpec.Type.Double:
1271 case BuiltinTypeSpec.Type.Decimal:
1273 primitive_type = true;
1276 primitive_type = false;
1278 // ++/-- on pointer variables of all types except void*
1279 if (type.IsPointer) {
1280 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1281 Error_VoidPointerOperation (ec);
1287 Expression best_source = null;
1288 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1289 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1291 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1295 if (best_source == null) {
1296 best_source = source;
1300 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1305 best_source = source;
1309 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1313 source = best_source;
1316 // ++/-- on enum types
1317 if (source == null && type.IsEnum)
1320 if (source == null) {
1321 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1328 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1329 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1330 operation = new Binary (op, source, one);
1331 operation = operation.Resolve (ec);
1332 if (operation == null)
1333 throw new NotImplementedException ("should not be reached");
1335 if (operation.Type != type) {
1337 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1339 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1345 void EmitCode (EmitContext ec, bool is_expr)
1348 this.is_expr = is_expr;
1349 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1352 public override void Emit (EmitContext ec)
1355 // We use recurse to allow ourselfs to be the source
1356 // of an assignment. This little hack prevents us from
1357 // having to allocate another expression
1360 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1368 EmitCode (ec, true);
1371 protected virtual void EmitOperation (EmitContext ec)
1373 operation.Emit (ec);
1376 public override void EmitStatement (EmitContext ec)
1378 EmitCode (ec, false);
1381 public override void FlowAnalysis (FlowAnalysisContext fc)
1383 expr.FlowAnalysis (fc);
1387 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1389 string GetOperatorExpressionTypeName ()
1391 return IsDecrement ? "Decrement" : "Increment";
1395 get { return (mode & Mode.IsDecrement) != 0; }
1399 public override SLE.Expression MakeExpression (BuilderContext ctx)
1401 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1402 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1403 return SLE.Expression.Assign (target, source);
1406 public static string OperName (Mode oper)
1408 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1411 protected override void CloneTo (CloneContext clonectx, Expression t)
1413 UnaryMutator target = (UnaryMutator) t;
1415 target.expr = expr.Clone (clonectx);
1418 public override object Accept (StructuralVisitor visitor)
1420 return visitor.Visit (this);
1426 // Base class for the `is' and `as' operators
1428 public abstract class Probe : Expression
1430 public Expression ProbeType;
1431 protected Expression expr;
1432 protected TypeSpec probe_type_expr;
1434 protected Probe (Expression expr, Expression probe_type, Location l)
1436 ProbeType = probe_type;
1441 public Expression Expr {
1447 public override bool ContainsEmitWithAwait ()
1449 return expr.ContainsEmitWithAwait ();
1452 protected Expression ResolveCommon (ResolveContext rc)
1454 expr = expr.Resolve (rc);
1458 ResolveProbeType (rc);
1459 if (probe_type_expr == null)
1462 if (probe_type_expr.IsStatic) {
1463 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1464 probe_type_expr.GetSignatureForError ());
1468 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1469 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1474 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1475 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1483 protected virtual void ResolveProbeType (ResolveContext rc)
1485 probe_type_expr = ProbeType.ResolveAsType (rc);
1488 public override void EmitSideEffect (EmitContext ec)
1490 expr.EmitSideEffect (ec);
1493 public override void EmitPrepare (EmitContext ec)
1495 expr.EmitPrepare (ec);
1498 public override void FlowAnalysis (FlowAnalysisContext fc)
1500 expr.FlowAnalysis (fc);
1503 public override bool HasConditionalAccess ()
1505 return expr.HasConditionalAccess ();
1508 protected abstract string OperatorName { get; }
1510 protected override void CloneTo (CloneContext clonectx, Expression t)
1512 Probe target = (Probe) t;
1514 target.expr = expr.Clone (clonectx);
1515 target.ProbeType = ProbeType.Clone (clonectx);
1521 /// Implementation of the `is' operator.
1523 public class Is : Probe
1525 Nullable.Unwrap expr_unwrap;
1526 MethodSpec number_mg;
1527 Arguments number_args;
1529 public Is (Expression expr, Expression probe_type, Location l)
1530 : base (expr, probe_type, l)
1534 protected override string OperatorName {
1535 get { return "is"; }
1538 public LocalVariable Variable { get; set; }
1540 public override Expression CreateExpressionTree (ResolveContext ec)
1542 if (Variable != null)
1543 ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
1545 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1546 expr.CreateExpressionTree (ec),
1547 new TypeOf (probe_type_expr, loc));
1549 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1552 Expression CreateConstantResult (ResolveContext rc, bool result)
1555 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1556 probe_type_expr.GetSignatureForError ());
1558 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1559 probe_type_expr.GetSignatureForError ());
1561 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1562 return expr.IsSideEffectFree ?
1563 ReducedExpression.Create (c, this) :
1564 new SideEffectConstant (c, this, loc);
1567 public override void Emit (EmitContext ec)
1569 if (probe_type_expr == null) {
1570 if (ProbeType is WildcardPattern) {
1571 expr.EmitSideEffect (ec);
1572 ProbeType.Emit (ec);
1574 EmitPatternMatch (ec);
1581 if (expr_unwrap == null) {
1583 ec.Emit (OpCodes.Cgt_Un);
1587 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1589 if (probe_type_expr == null) {
1590 EmitPatternMatch (ec);
1595 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1598 public override void EmitPrepare (EmitContext ec)
1600 base.EmitPrepare (ec);
1602 if (Variable != null)
1603 Variable.CreateBuilder (ec);
1606 void EmitPatternMatch (EmitContext ec)
1608 var no_match = ec.DefineLabel ();
1609 var end = ec.DefineLabel ();
1611 if (expr_unwrap != null) {
1612 expr_unwrap.EmitCheck (ec);
1614 if (ProbeType.IsNull) {
1616 ec.Emit (OpCodes.Ceq);
1620 ec.Emit (OpCodes.Brfalse_S, no_match);
1621 expr_unwrap.Emit (ec);
1622 ProbeType.Emit (ec);
1623 ec.Emit (OpCodes.Ceq);
1624 ec.Emit (OpCodes.Br_S, end);
1625 ec.MarkLabel (no_match);
1631 if (number_args != null && number_args.Count == 3) {
1632 var ce = new CallEmitter ();
1633 ce.Emit (ec, number_mg, number_args, loc);
1637 var probe_type = ProbeType.Type;
1640 ec.Emit (OpCodes.Isinst, probe_type);
1641 ec.Emit (OpCodes.Dup);
1642 ec.Emit (OpCodes.Brfalse, no_match);
1644 bool complex_pattern = ProbeType is ComplexPatternExpression;
1645 Label prev = ec.RecursivePatternLabel;
1646 if (complex_pattern)
1647 ec.RecursivePatternLabel = ec.DefineLabel ();
1649 if (number_mg != null) {
1650 var ce = new CallEmitter ();
1651 ce.Emit (ec, number_mg, number_args, loc);
1653 if (TypeSpec.IsValueType (probe_type))
1654 ec.Emit (OpCodes.Unbox_Any, probe_type);
1656 ProbeType.Emit (ec);
1657 if (complex_pattern) {
1660 ec.Emit (OpCodes.Ceq);
1663 ec.Emit (OpCodes.Br_S, end);
1664 ec.MarkLabel (no_match);
1666 ec.Emit (OpCodes.Pop);
1668 if (complex_pattern)
1669 ec.MarkLabel (ec.RecursivePatternLabel);
1671 ec.RecursivePatternLabel = prev;
1677 void EmitLoad (EmitContext ec)
1679 Label no_value_label = new Label ();
1681 if (expr_unwrap != null) {
1682 expr_unwrap.EmitCheck (ec);
1684 if (Variable == null)
1687 ec.Emit (OpCodes.Dup);
1688 no_value_label = ec.DefineLabel ();
1689 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1690 expr_unwrap.Emit (ec);
1694 // Only to make verifier happy
1695 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1696 ec.Emit (OpCodes.Box, expr.Type);
1698 ec.Emit (OpCodes.Isinst, probe_type_expr);
1701 if (Variable != null) {
1702 bool value_on_stack;
1703 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1704 ec.Emit (OpCodes.Dup);
1705 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1706 value_on_stack = true;
1708 value_on_stack = false;
1712 // It's ok to have variable builder create out of order. It simplified emit
1713 // of statements like while (condition) { }
1715 if (!Variable.Created)
1716 Variable.CreateBuilder (ec);
1718 Variable.EmitAssign (ec);
1720 if (expr_unwrap != null) {
1721 ec.MarkLabel (no_value_label);
1722 } else if (!value_on_stack) {
1728 protected override Expression DoResolve (ResolveContext rc)
1730 if (ResolveCommon (rc) == null)
1733 type = rc.BuiltinTypes.Bool;
1734 eclass = ExprClass.Value;
1736 if (probe_type_expr == null)
1737 return ResolveMatchingExpression (rc);
1739 var res = ResolveResultExpression (rc);
1740 if (Variable != null) {
1741 if (res is Constant)
1742 throw new NotImplementedException ("constant in type pattern matching");
1744 Variable.Type = probe_type_expr;
1745 var bc = rc as BlockContext;
1747 Variable.PrepareAssignmentAnalysis (bc);
1753 public override void FlowAnalysis (FlowAnalysisContext fc)
1755 base.FlowAnalysis (fc);
1757 if (Variable != null)
1758 fc.SetVariableAssigned (Variable.VariableInfo, true);
1761 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
1763 if (Variable == null) {
1764 base.FlowAnalysisConditional (fc);
1768 expr.FlowAnalysis (fc);
1770 fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
1771 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1773 fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
1776 protected override void ResolveProbeType (ResolveContext rc)
1778 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1779 if (ProbeType is PatternExpression) {
1780 ProbeType.Resolve (rc);
1785 // Have to use session recording because we don't have reliable type probing
1786 // mechanism (similar issue as in attributes resolving)
1788 // TODO: This is still wrong because ResolveAsType can be destructive
1790 var type_printer = new SessionReportPrinter ();
1791 var prev_recorder = rc.Report.SetPrinter (type_printer);
1793 probe_type_expr = ProbeType.ResolveAsType (rc);
1794 type_printer.EndSession ();
1796 if (probe_type_expr != null) {
1797 type_printer.Merge (rc.Report.Printer);
1798 rc.Report.SetPrinter (prev_recorder);
1802 var vexpr = ProbeType as VarExpr;
1803 if (vexpr != null && vexpr.InferType (rc, expr)) {
1804 probe_type_expr = vexpr.Type;
1805 rc.Report.SetPrinter (prev_recorder);
1809 var expr_printer = new SessionReportPrinter ();
1810 rc.Report.SetPrinter (expr_printer);
1811 ProbeType = ProbeType.Resolve (rc);
1812 expr_printer.EndSession ();
1814 if (ProbeType != null) {
1815 expr_printer.Merge (rc.Report.Printer);
1817 type_printer.Merge (rc.Report.Printer);
1820 rc.Report.SetPrinter (prev_recorder);
1824 base.ResolveProbeType (rc);
1827 Expression ResolveMatchingExpression (ResolveContext rc)
1829 var mc = ProbeType as Constant;
1831 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1832 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1837 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1839 var c = Expr as Constant;
1841 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1846 if (Expr.Type.IsNullableType) {
1847 expr_unwrap = new Nullable.Unwrap (Expr);
1848 expr_unwrap.Resolve (rc);
1849 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1850 } else if (ProbeType.Type == Expr.Type) {
1851 // TODO: Better error handling
1852 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1853 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1854 var helper = rc.Module.CreatePatterMatchingHelper ();
1855 number_mg = helper.NumberMatcher.Spec;
1858 // There are actually 3 arguments but the first one is already on the stack
1860 number_args = new Arguments (3);
1861 if (!ProbeType.Type.IsEnum)
1862 number_args.Add (new Argument (Expr));
1864 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1865 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1871 if (ProbeType is PatternExpression) {
1872 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1873 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1879 // TODO: Better error message
1880 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1884 Expression ResolveResultExpression (ResolveContext ec)
1886 if (Variable != null) {
1887 if (expr is NullLiteral) {
1888 ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
1892 CheckExpressionVariable (ec);
1895 TypeSpec d = expr.Type;
1896 bool d_is_nullable = false;
1899 // If E is a method group or the null literal, or if the type of E is a reference
1900 // type or a nullable type and the value of E is null, the result is false
1903 return CreateConstantResult (ec, false);
1905 if (d.IsNullableType) {
1906 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1907 if (!ut.IsGenericParameter) {
1909 d_is_nullable = true;
1913 TypeSpec t = probe_type_expr;
1914 bool t_is_nullable = false;
1915 if (t.IsNullableType) {
1916 if (Variable != null) {
1917 ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
1918 t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
1921 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1922 if (!ut.IsGenericParameter) {
1924 t_is_nullable = true;
1931 // D and T are the same value types but D can be null
1933 if (d_is_nullable && !t_is_nullable) {
1934 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1939 // The result is true if D and T are the same value types
1941 return CreateConstantResult (ec, true);
1944 var tp = d as TypeParameterSpec;
1946 return ResolveGenericParameter (ec, t, tp);
1949 // An unboxing conversion exists
1951 if (Convert.ExplicitReferenceConversionExists (d, t))
1955 // open generic type
1957 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1960 var tps = t as TypeParameterSpec;
1962 return ResolveGenericParameter (ec, d, tps);
1964 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1965 if (Variable != null) {
1966 ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
1968 ec.Report.Warning (1981, 3, loc,
1969 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1970 OperatorName, t.GetSignatureForError ());
1974 if (TypeManager.IsGenericParameter (d))
1975 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1977 if (TypeSpec.IsValueType (d)) {
1978 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1979 if (d_is_nullable && !t_is_nullable) {
1980 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1984 return CreateConstantResult (ec, true);
1987 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1988 var c = expr as Constant;
1990 return CreateConstantResult (ec, !c.IsNull);
1993 // Do not optimize for imported type or dynamic type
1995 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1996 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
2000 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
2004 // Turn is check into simple null check for implicitly convertible reference types
2006 return ReducedExpression.Create (
2007 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
2011 if (Convert.ExplicitReferenceConversionExists (d, t))
2015 // open generic type
2017 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
2022 return CreateConstantResult (ec, false);
2025 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
2027 if (t.IsReferenceType) {
2029 return CreateConstantResult (ec, false);
2032 if (expr.Type.IsGenericParameter) {
2033 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2034 return CreateConstantResult (ec, true);
2036 expr = new BoxedCast (expr, d);
2042 public override object Accept (StructuralVisitor visitor)
2044 return visitor.Visit (this);
2048 class WildcardPattern : PatternExpression
2050 public WildcardPattern (Location loc)
2055 protected override Expression DoResolve (ResolveContext rc)
2057 eclass = ExprClass.Value;
2058 type = rc.BuiltinTypes.Object;
2062 public override void Emit (EmitContext ec)
2068 class RecursivePattern : ComplexPatternExpression
2070 MethodGroupExpr operator_mg;
2071 Arguments operator_args;
2073 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2074 : base (typeExpresion, loc)
2076 Arguments = arguments;
2079 public Arguments Arguments { get; private set; }
2081 protected override Expression DoResolve (ResolveContext rc)
2083 type = TypeExpression.ResolveAsType (rc);
2087 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2088 if (operators == null) {
2089 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2093 var ops = FindMatchingOverloads (operators);
2095 // TODO: better error message
2096 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2101 Arguments.Resolve (rc, out dynamic_args);
2103 throw new NotImplementedException ("dynamic argument");
2105 var op = FindBestOverload (rc, ops);
2107 // TODO: better error message
2108 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2112 var op_types = op.Parameters.Types;
2113 operator_args = new Arguments (op_types.Length);
2114 operator_args.Add (new Argument (new EmptyExpression (type)));
2116 for (int i = 0; i < Arguments.Count; ++i) {
2117 // TODO: Needs releasing optimization
2118 var lt = new LocalTemporary (op_types [i + 1]);
2119 operator_args.Add (new Argument (lt, Argument.AType.Out));
2121 if (comparisons == null)
2122 comparisons = new Expression[Arguments.Count];
2127 var arg = Arguments [i];
2128 var named = arg as NamedArgument;
2129 if (named != null) {
2130 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2131 expr = Arguments [arg_comp_index].Expr;
2137 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2140 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2142 eclass = ExprClass.Value;
2146 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2148 int arg_count = Arguments.Count + 1;
2149 List<MethodSpec> best = null;
2150 foreach (MethodSpec method in members) {
2151 var pm = method.Parameters;
2152 if (pm.Count != arg_count)
2155 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2157 for (int ii = 1; ii < pm.Count; ++ii) {
2158 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2168 best = new List<MethodSpec> ();
2176 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2178 for (int ii = 0; ii < Arguments.Count; ++ii) {
2179 var arg = Arguments [ii];
2180 var expr = arg.Expr;
2181 if (expr is WildcardPattern)
2184 var na = arg as NamedArgument;
2185 for (int i = 0; i < methods.Count; ++i) {
2186 var pd = methods [i].Parameters;
2190 index = pd.GetParameterIndexByName (na.Name);
2192 methods.RemoveAt (i--);
2199 var m = pd.Types [index];
2200 if (!Convert.ImplicitConversionExists (rc, expr, m))
2201 methods.RemoveAt (i--);
2205 if (methods.Count != 1)
2211 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2213 operator_mg.EmitCall (ec, operator_args, false);
2214 ec.Emit (OpCodes.Brfalse, target);
2216 base.EmitBranchable (ec, target, on_true);
2219 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2221 if (expr is WildcardPattern)
2222 return new EmptyExpression (expr.Type);
2224 var recursive = expr as RecursivePattern;
2225 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2229 if (recursive != null) {
2230 recursive.SetParentInstance (lt);
2234 // TODO: Better error handling
2235 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2238 public void SetParentInstance (Expression instance)
2240 operator_args [0] = new Argument (instance);
2244 class PropertyPattern : ComplexPatternExpression
2246 LocalTemporary instance;
2248 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2249 : base (typeExpresion, loc)
2254 public List<PropertyPatternMember> Members { get; private set; }
2256 protected override Expression DoResolve (ResolveContext rc)
2258 type = TypeExpression.ResolveAsType (rc);
2262 comparisons = new Expression[Members.Count];
2264 // TODO: optimize when source is VariableReference, it'd save dup+pop
2265 instance = new LocalTemporary (type);
2267 for (int i = 0; i < Members.Count; i++) {
2268 var lookup = Members [i];
2270 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2271 if (member == null) {
2272 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2273 if (member != null) {
2274 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2279 if (member == null) {
2280 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2284 var pe = member as PropertyExpr;
2285 if (pe == null || member is FieldExpr) {
2286 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2290 // TODO: Obsolete checks
2291 // TODO: check accessibility
2292 if (pe != null && !pe.PropertyInfo.HasGet) {
2293 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2297 var expr = lookup.Expr.Resolve (rc);
2301 var me = (MemberExpr)member;
2302 me.InstanceExpression = instance;
2304 comparisons [i] = ResolveComparison (rc, expr, me);
2307 eclass = ExprClass.Value;
2311 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2313 if (expr is WildcardPattern)
2314 return new EmptyExpression (expr.Type);
2316 return new Is (instance, expr, expr.Location).Resolve (rc);
2319 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2321 instance.Store (ec);
2323 base.EmitBranchable (ec, target, on_true);
2327 class PropertyPatternMember
2329 public PropertyPatternMember (string name, Expression expr, Location loc)
2336 public string Name { get; private set; }
2337 public Expression Expr { get; private set; }
2338 public Location Location { get; private set; }
2341 abstract class PatternExpression : Expression
2343 protected PatternExpression (Location loc)
2348 public override Expression CreateExpressionTree (ResolveContext ec)
2350 throw new NotImplementedException ();
2354 abstract class ComplexPatternExpression : PatternExpression
2356 protected Expression[] comparisons;
2358 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2361 TypeExpression = typeExpresion;
2364 public ATypeNameExpression TypeExpression { get; private set; }
2366 public override void Emit (EmitContext ec)
2368 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2371 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2373 if (comparisons != null) {
2374 foreach (var comp in comparisons) {
2375 comp.EmitBranchable (ec, target, false);
2382 /// Implementation of the `as' operator.
2384 public class As : Probe {
2386 public As (Expression expr, Expression probe_type, Location l)
2387 : base (expr, probe_type, l)
2391 protected override string OperatorName {
2392 get { return "as"; }
2395 public override Expression CreateExpressionTree (ResolveContext ec)
2397 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2398 expr.CreateExpressionTree (ec),
2399 new TypeOf (probe_type_expr, loc));
2401 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2404 public override void Emit (EmitContext ec)
2408 ec.Emit (OpCodes.Isinst, type);
2410 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2411 ec.Emit (OpCodes.Unbox_Any, type);
2414 protected override Expression DoResolve (ResolveContext ec)
2416 if (ResolveCommon (ec) == null)
2419 type = probe_type_expr;
2420 eclass = ExprClass.Value;
2421 TypeSpec etype = expr.Type;
2423 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) {
2424 ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type");
2425 type = InternalType.ErrorType;
2430 type = InternalType.ErrorType;
2434 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2435 if (TypeManager.IsGenericParameter (type)) {
2436 ec.Report.Error (413, loc,
2437 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2438 probe_type_expr.GetSignatureForError ());
2440 ec.Report.Error (77, loc,
2441 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2442 type.GetSignatureForError ());
2447 if (expr.IsNull && type.IsNullableType) {
2448 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2451 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2452 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2456 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2458 e = EmptyCast.Create (e, type);
2459 return ReducedExpression.Create (e, this).Resolve (ec);
2462 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2463 if (TypeManager.IsGenericParameter (etype))
2464 expr = new BoxedCast (expr, etype);
2469 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2470 expr = new BoxedCast (expr, etype);
2474 if (etype != InternalType.ErrorType) {
2475 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2476 etype.GetSignatureForError (), type.GetSignatureForError ());
2482 public override object Accept (StructuralVisitor visitor)
2484 return visitor.Visit (this);
2489 // This represents a typecast in the source language.
2491 public class Cast : ShimExpression {
2492 Expression target_type;
2494 public Cast (Expression cast_type, Expression expr, Location loc)
2497 this.target_type = cast_type;
2501 public Expression TargetType {
2502 get { return target_type; }
2505 protected override Expression DoResolve (ResolveContext ec)
2507 expr = expr.Resolve (ec);
2511 type = target_type.ResolveAsType (ec);
2515 if (type.IsStatic) {
2516 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2520 if (type.IsPointer) {
2521 if (ec.CurrentIterator != null) {
2522 UnsafeInsideIteratorError (ec, loc);
2523 } else if (!ec.IsUnsafe) {
2524 UnsafeError (ec, loc);
2528 eclass = ExprClass.Value;
2530 Constant c = expr as Constant;
2532 c = c.Reduce (ec, type);
2537 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2539 return EmptyCast.Create (res, type);
2544 protected override void CloneTo (CloneContext clonectx, Expression t)
2546 Cast target = (Cast) t;
2548 target.target_type = target_type.Clone (clonectx);
2549 target.expr = expr.Clone (clonectx);
2552 public override object Accept (StructuralVisitor visitor)
2554 return visitor.Visit (this);
2558 public class ImplicitCast : ShimExpression
2562 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2565 this.loc = expr.Location;
2567 this.arrayAccess = arrayAccess;
2570 protected override Expression DoResolve (ResolveContext ec)
2572 expr = expr.Resolve (ec);
2577 expr = ConvertExpressionToArrayIndex (ec, expr);
2579 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2585 public class DeclarationExpression : Expression, IMemoryLocation
2587 LocalVariableReference lvr;
2589 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2591 VariableType = variableType;
2592 Variable = variable;
2593 this.loc = variable.Location;
2596 public LocalVariable Variable { get; set; }
2597 public Expression Initializer { get; set; }
2598 public FullNamedExpression VariableType { get; set; }
2600 public void AddressOf (EmitContext ec, AddressOp mode)
2602 Variable.CreateBuilder (ec);
2604 if (Initializer != null) {
2605 lvr.EmitAssign (ec, Initializer, false, false);
2608 lvr.AddressOf (ec, mode);
2611 protected override void CloneTo (CloneContext clonectx, Expression t)
2613 var target = (DeclarationExpression) t;
2615 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2617 if (Initializer != null)
2618 target.Initializer = Initializer.Clone (clonectx);
2621 public override Expression CreateExpressionTree (ResolveContext rc)
2623 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2627 bool DoResolveCommon (ResolveContext rc)
2629 CheckExpressionVariable (rc);
2631 var var_expr = VariableType as VarExpr;
2632 if (var_expr != null) {
2633 type = InternalType.VarOutType;
2635 type = VariableType.ResolveAsType (rc);
2640 if (Initializer != null) {
2641 Initializer = Initializer.Resolve (rc);
2643 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2644 type = var_expr.Type;
2648 Variable.Type = type;
2649 lvr = new LocalVariableReference (Variable, loc);
2651 eclass = ExprClass.Variable;
2655 protected override Expression DoResolve (ResolveContext rc)
2657 if (DoResolveCommon (rc))
2663 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2665 if (lvr == null && DoResolveCommon (rc))
2666 lvr.ResolveLValue (rc, right_side);
2671 public override void Emit (EmitContext ec)
2673 throw new NotImplementedException ();
2678 // C# 2.0 Default value expression
2680 public class DefaultValueExpression : Expression
2684 public DefaultValueExpression (Expression expr, Location loc)
2690 public Expression Expr {
2696 public override bool IsSideEffectFree {
2702 public override bool ContainsEmitWithAwait ()
2707 public override Expression CreateExpressionTree (ResolveContext ec)
2709 Arguments args = new Arguments (2);
2710 args.Add (new Argument (this));
2711 args.Add (new Argument (new TypeOf (type, loc)));
2712 return CreateExpressionFactoryCall (ec, "Constant", args);
2715 protected override Expression DoResolve (ResolveContext ec)
2717 type = expr.ResolveAsType (ec);
2721 if (type.IsStatic) {
2722 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2726 return new NullLiteral (Location).ConvertImplicitly (type);
2728 if (TypeSpec.IsReferenceType (type))
2729 return new NullConstant (type, loc);
2731 Constant c = New.Constantify (type, expr.Location);
2735 eclass = ExprClass.Variable;
2739 public override void Emit (EmitContext ec)
2741 LocalTemporary temp_storage = new LocalTemporary(type);
2743 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2744 ec.Emit(OpCodes.Initobj, type);
2745 temp_storage.Emit(ec);
2746 temp_storage.Release (ec);
2750 public override SLE.Expression MakeExpression (BuilderContext ctx)
2752 return SLE.Expression.Default (type.GetMetaInfo ());
2756 protected override void CloneTo (CloneContext clonectx, Expression t)
2758 DefaultValueExpression target = (DefaultValueExpression) t;
2760 target.expr = expr.Clone (clonectx);
2763 public override object Accept (StructuralVisitor visitor)
2765 return visitor.Visit (this);
2770 /// Binary operators
2772 public class Binary : Expression, IDynamicBinder
2774 public class PredefinedOperator
2776 protected readonly TypeSpec left;
2777 protected readonly TypeSpec right;
2778 protected readonly TypeSpec left_unwrap;
2779 protected readonly TypeSpec right_unwrap;
2780 public readonly Operator OperatorsMask;
2781 public TypeSpec ReturnType;
2783 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2784 : this (ltype, rtype, op_mask, ltype)
2788 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2789 : this (type, type, op_mask, return_type)
2793 public PredefinedOperator (TypeSpec type, Operator op_mask)
2794 : this (type, type, op_mask, type)
2798 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2800 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2801 throw new InternalErrorException ("Only masked values can be used");
2803 if ((op_mask & Operator.NullableMask) != 0) {
2804 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2805 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2807 left_unwrap = ltype;
2808 right_unwrap = rtype;
2813 this.OperatorsMask = op_mask;
2814 this.ReturnType = return_type;
2817 public bool IsLifted {
2819 return (OperatorsMask & Operator.NullableMask) != 0;
2823 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2827 var left_expr = b.left;
2828 var right_expr = b.right;
2830 b.type = ReturnType;
2833 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2834 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2835 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2838 if (right_expr.IsNull) {
2839 if ((b.oper & Operator.EqualityMask) != 0) {
2840 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2841 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2842 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2843 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2844 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2846 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2847 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2849 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2850 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2852 return b.CreateLiftedValueTypeResult (rc, left);
2854 } else if (left_expr.IsNull) {
2855 if ((b.oper & Operator.EqualityMask) != 0) {
2856 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2857 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2858 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2859 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2860 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2862 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2863 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2865 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2866 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2868 return b.CreateLiftedValueTypeResult (rc, right);
2874 // A user operators does not support multiple user conversions, but decimal type
2875 // is considered to be predefined type therefore we apply predefined operators rules
2876 // and then look for decimal user-operator implementation
2878 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2879 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2880 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2882 return b.ResolveUserOperator (rc, b.left, b.right);
2885 c = right_expr as Constant;
2887 if (c.IsDefaultValue) {
2891 // (expr + 0) to expr
2892 // (expr - 0) to expr
2893 // (bool? | false) to bool?
2895 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2896 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2897 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2898 return ReducedExpression.Create (b.left, b).Resolve (rc);
2902 // Optimizes (value &/&& 0) to 0
2904 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2905 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2906 return ReducedExpression.Create (side_effect, b);
2910 // Optimizes (bool? & true) to bool?
2912 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2913 return ReducedExpression.Create (b.left, b).Resolve (rc);
2917 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2918 return ReducedExpression.Create (b.left, b).Resolve (rc);
2920 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2921 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2925 c = b.left as Constant;
2927 if (c.IsDefaultValue) {
2931 // (0 + expr) to expr
2932 // (false | bool?) to bool?
2934 if (b.oper == Operator.Addition ||
2935 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2936 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2937 return ReducedExpression.Create (b.right, b).Resolve (rc);
2941 // Optimizes (false && expr) to false
2943 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2944 // No rhs side-effects
2945 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2946 return ReducedExpression.Create (c, b);
2950 // Optimizes (0 & value) to 0
2952 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2953 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2954 return ReducedExpression.Create (side_effect, b);
2958 // Optimizes (true & bool?) to bool?
2960 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2961 return ReducedExpression.Create (b.right, b).Resolve (rc);
2965 // Optimizes (true || expr) to true
2967 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2968 // No rhs side-effects
2969 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2970 return ReducedExpression.Create (c, b);
2974 if (b.oper == Operator.Multiply && c.IsOneInteger)
2975 return ReducedExpression.Create (b.right, b).Resolve (rc);
2979 var lifted = new Nullable.LiftedBinaryOperator (b);
2981 TypeSpec ltype, rtype;
2982 if (b.left.Type.IsNullableType) {
2983 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2984 ltype = left_unwrap;
2989 if (b.right.Type.IsNullableType) {
2990 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2991 rtype = right_unwrap;
2996 lifted.Left = b.left.IsNull ?
2997 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2998 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
3000 lifted.Right = b.right.IsNull ?
3001 Nullable.LiftedNull.Create (rtype, b.right.Location) :
3002 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
3004 return lifted.Resolve (rc);
3007 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3008 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3013 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3016 // We are dealing with primitive types only
3018 return left == ltype && ltype == rtype;
3021 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3024 if (left == lexpr.Type && right == rexpr.Type)
3027 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3028 Convert.ImplicitConversionExists (ec, rexpr, right);
3031 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3033 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3034 return best_operator;
3036 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3040 if (left != null && best_operator.left != null) {
3041 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3045 // When second argument is same as the first one, the result is same
3047 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3048 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3051 if (result == 0 || result > 2)
3054 return result == 1 ? best_operator : this;
3058 sealed class PredefinedStringOperator : PredefinedOperator
3060 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3061 : base (type, type, op_mask, retType)
3065 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3066 : base (ltype, rtype, op_mask, retType)
3070 public override Expression ConvertResult (ResolveContext ec, Binary b)
3073 // Use original expression for nullable arguments
3075 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3077 b.left = unwrap.Original;
3079 unwrap = b.right as Nullable.Unwrap;
3081 b.right = unwrap.Original;
3083 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3084 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3087 // Start a new concat expression using converted expression
3089 return StringConcat.Create (ec, b.left, b.right, b.loc);
3093 sealed class PredefinedEqualityOperator : PredefinedOperator
3095 MethodSpec equal_method, inequal_method;
3097 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3098 : base (arg, arg, Operator.EqualityMask, retType)
3102 public override Expression ConvertResult (ResolveContext ec, Binary b)
3104 b.type = ReturnType;
3106 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3107 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3109 Arguments args = new Arguments (2);
3110 args.Add (new Argument (b.left));
3111 args.Add (new Argument (b.right));
3114 if (b.oper == Operator.Equality) {
3115 if (equal_method == null) {
3116 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3117 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3118 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3119 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3121 throw new NotImplementedException (left.GetSignatureForError ());
3124 method = equal_method;
3126 if (inequal_method == null) {
3127 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3128 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3129 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3130 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3132 throw new NotImplementedException (left.GetSignatureForError ());
3135 method = inequal_method;
3138 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3142 class PredefinedPointerOperator : PredefinedOperator
3144 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3145 : base (ltype, rtype, op_mask)
3149 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3150 : base (ltype, rtype, op_mask, retType)
3154 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3155 : base (type, op_mask, return_type)
3159 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3162 if (!lexpr.Type.IsPointer)
3165 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3169 if (right == null) {
3170 if (!rexpr.Type.IsPointer)
3173 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3180 public override Expression ConvertResult (ResolveContext ec, Binary b)
3183 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3184 } else if (right != null) {
3185 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3188 TypeSpec r_type = ReturnType;
3189 Expression left_arg, right_arg;
3190 if (r_type == null) {
3193 right_arg = b.right;
3194 r_type = b.left.Type;
3198 r_type = b.right.Type;
3202 right_arg = b.right;
3205 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3210 public enum Operator {
3211 Multiply = 0 | ArithmeticMask,
3212 Division = 1 | ArithmeticMask,
3213 Modulus = 2 | ArithmeticMask,
3214 Addition = 3 | ArithmeticMask | AdditionMask,
3215 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3217 LeftShift = 5 | ShiftMask,
3218 RightShift = 6 | ShiftMask,
3220 LessThan = 7 | ComparisonMask | RelationalMask,
3221 GreaterThan = 8 | ComparisonMask | RelationalMask,
3222 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3223 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3224 Equality = 11 | ComparisonMask | EqualityMask,
3225 Inequality = 12 | ComparisonMask | EqualityMask,
3227 BitwiseAnd = 13 | BitwiseMask,
3228 ExclusiveOr = 14 | BitwiseMask,
3229 BitwiseOr = 15 | BitwiseMask,
3231 LogicalAnd = 16 | LogicalMask,
3232 LogicalOr = 17 | LogicalMask,
3237 ValuesOnlyMask = ArithmeticMask - 1,
3238 ArithmeticMask = 1 << 5,
3240 ComparisonMask = 1 << 7,
3241 EqualityMask = 1 << 8,
3242 BitwiseMask = 1 << 9,
3243 LogicalMask = 1 << 10,
3244 AdditionMask = 1 << 11,
3245 SubtractionMask = 1 << 12,
3246 RelationalMask = 1 << 13,
3248 DecomposedMask = 1 << 19,
3249 NullableMask = 1 << 20
3253 public enum State : byte
3257 UserOperatorsExcluded = 1 << 2
3260 readonly Operator oper;
3261 Expression left, right;
3263 ConvCast.Mode enum_conversion;
3265 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3266 : this (oper, left, right, State.Compound)
3270 public Binary (Operator oper, Expression left, Expression right, State state)
3271 : this (oper, left, right)
3276 public Binary (Operator oper, Expression left, Expression right)
3277 : this (oper, left, right, left.Location)
3281 public Binary (Operator oper, Expression left, Expression right, Location loc)
3291 public bool IsCompound {
3293 return (state & State.Compound) != 0;
3297 public Operator Oper {
3303 public Expression Left {
3309 public Expression Right {
3315 public override Location StartLocation {
3317 return left.StartLocation;
3324 /// Returns a stringified representation of the Operator
3326 string OperName (Operator oper)
3330 case Operator.Multiply:
3333 case Operator.Division:
3336 case Operator.Modulus:
3339 case Operator.Addition:
3342 case Operator.Subtraction:
3345 case Operator.LeftShift:
3348 case Operator.RightShift:
3351 case Operator.LessThan:
3354 case Operator.GreaterThan:
3357 case Operator.LessThanOrEqual:
3360 case Operator.GreaterThanOrEqual:
3363 case Operator.Equality:
3366 case Operator.Inequality:
3369 case Operator.BitwiseAnd:
3372 case Operator.BitwiseOr:
3375 case Operator.ExclusiveOr:
3378 case Operator.LogicalOr:
3381 case Operator.LogicalAnd:
3385 s = oper.ToString ();
3395 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3397 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3400 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3402 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3406 l = left.Type.GetSignatureForError ();
3407 r = right.Type.GetSignatureForError ();
3409 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3413 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3415 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3418 public override void FlowAnalysis (FlowAnalysisContext fc)
3421 // Optimized version when on-true/on-false data are not needed
3423 if ((oper & Operator.LogicalMask) == 0) {
3424 left.FlowAnalysis (fc);
3425 right.FlowAnalysis (fc);
3429 left.FlowAnalysisConditional (fc);
3430 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3431 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3433 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3434 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3435 right.FlowAnalysisConditional (fc);
3437 if (oper == Operator.LogicalOr)
3438 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3440 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3443 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3445 if ((oper & Operator.LogicalMask) == 0) {
3446 base.FlowAnalysisConditional (fc);
3450 left.FlowAnalysisConditional (fc);
3451 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3452 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3454 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3455 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3456 right.FlowAnalysisConditional (fc);
3458 var lc = left as Constant;
3459 if (oper == Operator.LogicalOr) {
3460 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3461 if (lc != null && lc.IsDefaultValue)
3462 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3464 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3466 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3467 if (lc != null && !lc.IsDefaultValue)
3468 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3470 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3475 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3477 string GetOperatorExpressionTypeName ()
3480 case Operator.Addition:
3481 return IsCompound ? "AddAssign" : "Add";
3482 case Operator.BitwiseAnd:
3483 return IsCompound ? "AndAssign" : "And";
3484 case Operator.BitwiseOr:
3485 return IsCompound ? "OrAssign" : "Or";
3486 case Operator.Division:
3487 return IsCompound ? "DivideAssign" : "Divide";
3488 case Operator.ExclusiveOr:
3489 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3490 case Operator.Equality:
3492 case Operator.GreaterThan:
3493 return "GreaterThan";
3494 case Operator.GreaterThanOrEqual:
3495 return "GreaterThanOrEqual";
3496 case Operator.Inequality:
3498 case Operator.LeftShift:
3499 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3500 case Operator.LessThan:
3502 case Operator.LessThanOrEqual:
3503 return "LessThanOrEqual";
3504 case Operator.LogicalAnd:
3506 case Operator.LogicalOr:
3508 case Operator.Modulus:
3509 return IsCompound ? "ModuloAssign" : "Modulo";
3510 case Operator.Multiply:
3511 return IsCompound ? "MultiplyAssign" : "Multiply";
3512 case Operator.RightShift:
3513 return IsCompound ? "RightShiftAssign" : "RightShift";
3514 case Operator.Subtraction:
3515 return IsCompound ? "SubtractAssign" : "Subtract";
3517 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3521 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3524 case Operator.Addition:
3525 return CSharp.Operator.OpType.Addition;
3526 case Operator.BitwiseAnd:
3527 case Operator.LogicalAnd:
3528 return CSharp.Operator.OpType.BitwiseAnd;
3529 case Operator.BitwiseOr:
3530 case Operator.LogicalOr:
3531 return CSharp.Operator.OpType.BitwiseOr;
3532 case Operator.Division:
3533 return CSharp.Operator.OpType.Division;
3534 case Operator.Equality:
3535 return CSharp.Operator.OpType.Equality;
3536 case Operator.ExclusiveOr:
3537 return CSharp.Operator.OpType.ExclusiveOr;
3538 case Operator.GreaterThan:
3539 return CSharp.Operator.OpType.GreaterThan;
3540 case Operator.GreaterThanOrEqual:
3541 return CSharp.Operator.OpType.GreaterThanOrEqual;
3542 case Operator.Inequality:
3543 return CSharp.Operator.OpType.Inequality;
3544 case Operator.LeftShift:
3545 return CSharp.Operator.OpType.LeftShift;
3546 case Operator.LessThan:
3547 return CSharp.Operator.OpType.LessThan;
3548 case Operator.LessThanOrEqual:
3549 return CSharp.Operator.OpType.LessThanOrEqual;
3550 case Operator.Modulus:
3551 return CSharp.Operator.OpType.Modulus;
3552 case Operator.Multiply:
3553 return CSharp.Operator.OpType.Multiply;
3554 case Operator.RightShift:
3555 return CSharp.Operator.OpType.RightShift;
3556 case Operator.Subtraction:
3557 return CSharp.Operator.OpType.Subtraction;
3559 throw new InternalErrorException (op.ToString ());
3563 public override bool ContainsEmitWithAwait ()
3565 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3568 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3573 case Operator.Multiply:
3574 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3575 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3576 opcode = OpCodes.Mul_Ovf;
3577 else if (!IsFloat (l))
3578 opcode = OpCodes.Mul_Ovf_Un;
3580 opcode = OpCodes.Mul;
3582 opcode = OpCodes.Mul;
3586 case Operator.Division:
3588 opcode = OpCodes.Div_Un;
3590 opcode = OpCodes.Div;
3593 case Operator.Modulus:
3595 opcode = OpCodes.Rem_Un;
3597 opcode = OpCodes.Rem;
3600 case Operator.Addition:
3601 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3602 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3603 opcode = OpCodes.Add_Ovf;
3604 else if (!IsFloat (l))
3605 opcode = OpCodes.Add_Ovf_Un;
3607 opcode = OpCodes.Add;
3609 opcode = OpCodes.Add;
3612 case Operator.Subtraction:
3613 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3614 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3615 opcode = OpCodes.Sub_Ovf;
3616 else if (!IsFloat (l))
3617 opcode = OpCodes.Sub_Ovf_Un;
3619 opcode = OpCodes.Sub;
3621 opcode = OpCodes.Sub;
3624 case Operator.RightShift:
3625 if (!(right is IntConstant)) {
3626 ec.EmitInt (GetShiftMask (l));
3627 ec.Emit (OpCodes.And);
3631 opcode = OpCodes.Shr_Un;
3633 opcode = OpCodes.Shr;
3636 case Operator.LeftShift:
3637 if (!(right is IntConstant)) {
3638 ec.EmitInt (GetShiftMask (l));
3639 ec.Emit (OpCodes.And);
3642 opcode = OpCodes.Shl;
3645 case Operator.Equality:
3646 opcode = OpCodes.Ceq;
3649 case Operator.Inequality:
3650 ec.Emit (OpCodes.Ceq);
3653 opcode = OpCodes.Ceq;
3656 case Operator.LessThan:
3658 opcode = OpCodes.Clt_Un;
3660 opcode = OpCodes.Clt;
3663 case Operator.GreaterThan:
3665 opcode = OpCodes.Cgt_Un;
3667 opcode = OpCodes.Cgt;
3670 case Operator.LessThanOrEqual:
3671 if (IsUnsigned (l) || IsFloat (l))
3672 ec.Emit (OpCodes.Cgt_Un);
3674 ec.Emit (OpCodes.Cgt);
3677 opcode = OpCodes.Ceq;
3680 case Operator.GreaterThanOrEqual:
3681 if (IsUnsigned (l) || IsFloat (l))
3682 ec.Emit (OpCodes.Clt_Un);
3684 ec.Emit (OpCodes.Clt);
3688 opcode = OpCodes.Ceq;
3691 case Operator.BitwiseOr:
3692 opcode = OpCodes.Or;
3695 case Operator.BitwiseAnd:
3696 opcode = OpCodes.And;
3699 case Operator.ExclusiveOr:
3700 opcode = OpCodes.Xor;
3704 throw new InternalErrorException (oper.ToString ());
3710 static int GetShiftMask (TypeSpec type)
3712 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3715 static bool IsUnsigned (TypeSpec t)
3717 switch (t.BuiltinType) {
3718 case BuiltinTypeSpec.Type.Char:
3719 case BuiltinTypeSpec.Type.UInt:
3720 case BuiltinTypeSpec.Type.ULong:
3721 case BuiltinTypeSpec.Type.UShort:
3722 case BuiltinTypeSpec.Type.Byte:
3729 static bool IsFloat (TypeSpec t)
3731 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3734 public Expression ResolveOperator (ResolveContext rc)
3736 eclass = ExprClass.Value;
3738 TypeSpec l = left.Type;
3739 TypeSpec r = right.Type;
3741 bool primitives_only = false;
3744 // Handles predefined primitive types
3746 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3747 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3748 if ((oper & Operator.ShiftMask) == 0) {
3749 if (!DoBinaryOperatorPromotion (rc))
3752 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3756 if (l.IsPointer || r.IsPointer)
3757 return ResolveOperatorPointer (rc, l, r);
3760 if ((state & State.UserOperatorsExcluded) == 0) {
3761 expr = ResolveUserOperator (rc, left, right);
3766 bool lenum = l.IsEnum;
3767 bool renum = r.IsEnum;
3768 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3772 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3773 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3778 if ((oper & Operator.BitwiseMask) != 0) {
3779 expr = EmptyCast.Create (expr, type);
3780 enum_conversion = GetEnumResultCast (type);
3782 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3783 expr = OptimizeAndOperation (expr);
3787 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3788 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3791 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3792 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3796 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3799 // We cannot break here there is also Enum + String possible match
3800 // which is not ambiguous with predefined enum operators
3803 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3804 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3808 } else if (l.IsDelegate || r.IsDelegate) {
3812 expr = ResolveOperatorDelegate (rc, l, r);
3814 // TODO: Can this be ambiguous
3822 // Equality operators are more complicated
3824 if ((oper & Operator.EqualityMask) != 0) {
3825 return ResolveEquality (rc, l, r, primitives_only);
3828 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3832 if (primitives_only)
3836 // Lifted operators have lower priority
3838 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3841 static bool IsEnumOrNullableEnum (TypeSpec type)
3843 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3847 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3848 // if 'left' is not an enumeration constant, create one from the type of 'right'
3849 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3852 case Operator.BitwiseOr:
3853 case Operator.BitwiseAnd:
3854 case Operator.ExclusiveOr:
3855 case Operator.Equality:
3856 case Operator.Inequality:
3857 case Operator.LessThan:
3858 case Operator.LessThanOrEqual:
3859 case Operator.GreaterThan:
3860 case Operator.GreaterThanOrEqual:
3861 if (left.Type.IsEnum)
3864 if (left.IsZeroInteger)
3865 return left.Reduce (ec, right.Type);
3869 case Operator.Addition:
3870 case Operator.Subtraction:
3873 case Operator.Multiply:
3874 case Operator.Division:
3875 case Operator.Modulus:
3876 case Operator.LeftShift:
3877 case Operator.RightShift:
3878 if (right.Type.IsEnum || left.Type.IsEnum)
3887 // The `|' operator used on types which were extended is dangerous
3889 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3891 OpcodeCast lcast = left as OpcodeCast;
3892 if (lcast != null) {
3893 if (IsUnsigned (lcast.UnderlyingType))
3897 OpcodeCast rcast = right as OpcodeCast;
3898 if (rcast != null) {
3899 if (IsUnsigned (rcast.UnderlyingType))
3903 if (lcast == null && rcast == null)
3906 // FIXME: consider constants
3908 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3909 ec.Report.Warning (675, 3, loc,
3910 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3911 ltype.GetSignatureForError ());
3914 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3916 return new PredefinedOperator[] {
3918 // Pointer arithmetic:
3920 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3921 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3922 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3923 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3925 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3926 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3927 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3928 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3931 // T* operator + (int y, T* x);
3932 // T* operator + (uint y, T *x);
3933 // T* operator + (long y, T *x);
3934 // T* operator + (ulong y, T *x);
3936 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3937 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3938 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3939 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3942 // long operator - (T* x, T *y)
3944 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3948 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3950 TypeSpec bool_type = types.Bool;
3953 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3954 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3955 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3956 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3957 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3958 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3959 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3961 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3962 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3963 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3964 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3965 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3966 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3967 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3969 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3970 // Remaining string operators are in lifted tables
3972 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3975 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3976 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3980 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3982 var types = module.Compiler.BuiltinTypes;
3985 // Not strictly lifted but need to be in second group otherwise expressions like
3986 // int + null would resolve to +(object, string) instead of +(int?, int?)
3988 var string_operators = new [] {
3989 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3990 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3993 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3994 if (nullable == null)
3995 return string_operators;
3997 var bool_type = types.Bool;
3999 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
4000 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4001 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4002 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4003 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4004 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4005 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4006 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4009 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4010 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4011 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4012 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4013 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4014 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4015 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4017 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4018 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4019 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4020 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4021 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4022 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4023 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4025 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4027 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4028 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4029 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4031 string_operators [0],
4032 string_operators [1]
4036 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4038 TypeSpec bool_type = types.Bool;
4041 new PredefinedEqualityOperator (types.String, bool_type),
4042 new PredefinedEqualityOperator (types.Delegate, bool_type),
4043 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4044 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4045 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4046 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4047 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4048 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4049 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4050 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4054 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4056 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4058 if (nullable == null)
4059 return new PredefinedOperator [0];
4061 var types = module.Compiler.BuiltinTypes;
4062 var bool_type = types.Bool;
4063 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4064 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4065 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4066 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4067 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4068 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4069 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4070 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4073 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4074 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4075 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4076 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4077 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4078 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4079 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4080 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4085 // 7.2.6.2 Binary numeric promotions
4087 bool DoBinaryOperatorPromotion (ResolveContext rc)
4089 TypeSpec ltype = left.Type;
4090 if (ltype.IsNullableType) {
4091 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4095 // This is numeric promotion code only
4097 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4100 TypeSpec rtype = right.Type;
4101 if (rtype.IsNullableType) {
4102 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4105 var lb = ltype.BuiltinType;
4106 var rb = rtype.BuiltinType;
4110 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4111 type = rc.BuiltinTypes.Decimal;
4112 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4113 type = rc.BuiltinTypes.Double;
4114 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4115 type = rc.BuiltinTypes.Float;
4116 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4117 type = rc.BuiltinTypes.ULong;
4119 if (IsSignedType (lb)) {
4120 expr = ConvertSignedConstant (left, type);
4124 } else if (IsSignedType (rb)) {
4125 expr = ConvertSignedConstant (right, type);
4131 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4132 type = rc.BuiltinTypes.Long;
4133 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4134 type = rc.BuiltinTypes.UInt;
4136 if (IsSignedType (lb)) {
4137 expr = ConvertSignedConstant (left, type);
4139 type = rc.BuiltinTypes.Long;
4140 } else if (IsSignedType (rb)) {
4141 expr = ConvertSignedConstant (right, type);
4143 type = rc.BuiltinTypes.Long;
4146 type = rc.BuiltinTypes.Int;
4149 if (ltype != type) {
4150 expr = PromoteExpression (rc, left, type);
4157 if (rtype != type) {
4158 expr = PromoteExpression (rc, right, type);
4168 static bool IsSignedType (BuiltinTypeSpec.Type type)
4171 case BuiltinTypeSpec.Type.Int:
4172 case BuiltinTypeSpec.Type.Short:
4173 case BuiltinTypeSpec.Type.SByte:
4174 case BuiltinTypeSpec.Type.Long:
4181 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4183 var c = expr as Constant;
4187 return c.ConvertImplicitly (type);
4190 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4192 if (expr.Type.IsNullableType) {
4193 return Convert.ImplicitConversionStandard (rc, expr,
4194 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4197 var c = expr as Constant;
4199 return c.ConvertImplicitly (type);
4201 return Convert.ImplicitNumericConversion (expr, type);
4204 protected override Expression DoResolve (ResolveContext ec)
4209 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4210 left = ((ParenthesizedExpression) left).Expr;
4211 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4215 if (left.eclass == ExprClass.Type) {
4216 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4220 left = left.Resolve (ec);
4225 right = right.Resolve (ec);
4229 Constant lc = left as Constant;
4230 Constant rc = right as Constant;
4232 // The conversion rules are ignored in enum context but why
4233 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4234 lc = EnumLiftUp (ec, lc, rc);
4236 rc = EnumLiftUp (ec, rc, lc);
4239 if (rc != null && lc != null) {
4240 int prev_e = ec.Report.Errors;
4241 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4242 if (e != null || ec.Report.Errors != prev_e)
4246 // Comparison warnings
4247 if ((oper & Operator.ComparisonMask) != 0) {
4248 if (left.Equals (right)) {
4249 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4251 CheckOutOfRangeComparison (ec, lc, right.Type);
4252 CheckOutOfRangeComparison (ec, rc, left.Type);
4255 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4256 return DoResolveDynamic (ec);
4258 return DoResolveCore (ec, left, right);
4261 Expression DoResolveDynamic (ResolveContext rc)
4264 var rt = right.Type;
4265 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4266 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4267 Error_OperatorCannotBeApplied (rc, left, right);
4274 // Special handling for logical boolean operators which require rhs not to be
4275 // evaluated based on lhs value
4277 if ((oper & Operator.LogicalMask) != 0) {
4278 Expression cond_left, cond_right, expr;
4280 args = new Arguments (2);
4282 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4283 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4285 var cond_args = new Arguments (1);
4286 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4289 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4290 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4292 left = temp.CreateReferenceExpression (rc, loc);
4293 if (oper == Operator.LogicalAnd) {
4294 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4297 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4301 args.Add (new Argument (left));
4302 args.Add (new Argument (right));
4303 cond_right = new DynamicExpressionStatement (this, args, loc);
4305 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4307 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4308 rc.Report.Error (7083, left.Location,
4309 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4310 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4314 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4315 args.Add (new Argument (right));
4316 right = new DynamicExpressionStatement (this, args, loc);
4319 // bool && dynamic => (temp = left) ? temp && right : temp;
4320 // bool || dynamic => (temp = left) ? temp : temp || right;
4322 if (oper == Operator.LogicalAnd) {
4324 cond_right = temp.CreateReferenceExpression (rc, loc);
4326 cond_left = temp.CreateReferenceExpression (rc, loc);
4330 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4333 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4336 args = new Arguments (2);
4337 args.Add (new Argument (left));
4338 args.Add (new Argument (right));
4339 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4342 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4344 Expression expr = ResolveOperator (ec);
4346 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4348 if (left == null || right == null)
4349 throw new InternalErrorException ("Invalid conversion");
4351 if (oper == Operator.BitwiseOr)
4352 CheckBitwiseOrOnSignExtended (ec);
4357 public override SLE.Expression MakeExpression (BuilderContext ctx)
4359 return MakeExpression (ctx, left, right);
4362 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4364 var le = left.MakeExpression (ctx);
4365 var re = right.MakeExpression (ctx);
4366 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4369 case Operator.Addition:
4370 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4371 case Operator.BitwiseAnd:
4372 return SLE.Expression.And (le, re);
4373 case Operator.BitwiseOr:
4374 return SLE.Expression.Or (le, re);
4375 case Operator.Division:
4376 return SLE.Expression.Divide (le, re);
4377 case Operator.Equality:
4378 return SLE.Expression.Equal (le, re);
4379 case Operator.ExclusiveOr:
4380 return SLE.Expression.ExclusiveOr (le, re);
4381 case Operator.GreaterThan:
4382 return SLE.Expression.GreaterThan (le, re);
4383 case Operator.GreaterThanOrEqual:
4384 return SLE.Expression.GreaterThanOrEqual (le, re);
4385 case Operator.Inequality:
4386 return SLE.Expression.NotEqual (le, re);
4387 case Operator.LeftShift:
4388 return SLE.Expression.LeftShift (le, re);
4389 case Operator.LessThan:
4390 return SLE.Expression.LessThan (le, re);
4391 case Operator.LessThanOrEqual:
4392 return SLE.Expression.LessThanOrEqual (le, re);
4393 case Operator.LogicalAnd:
4394 return SLE.Expression.AndAlso (le, re);
4395 case Operator.LogicalOr:
4396 return SLE.Expression.OrElse (le, re);
4397 case Operator.Modulus:
4398 return SLE.Expression.Modulo (le, re);
4399 case Operator.Multiply:
4400 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4401 case Operator.RightShift:
4402 return SLE.Expression.RightShift (le, re);
4403 case Operator.Subtraction:
4404 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4406 throw new NotImplementedException (oper.ToString ());
4411 // D operator + (D x, D y)
4412 // D operator - (D x, D y)
4414 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4416 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4418 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4419 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4424 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4425 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4435 MethodSpec method = null;
4436 Arguments args = new Arguments (2);
4437 args.Add (new Argument (left));
4438 args.Add (new Argument (right));
4440 if (oper == Operator.Addition) {
4441 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4442 } else if (oper == Operator.Subtraction) {
4443 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4447 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4449 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4450 return new ClassCast (expr, l);
4454 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4456 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4459 // bool operator == (E x, E y);
4460 // bool operator != (E x, E y);
4461 // bool operator < (E x, E y);
4462 // bool operator > (E x, E y);
4463 // bool operator <= (E x, E y);
4464 // bool operator >= (E x, E y);
4466 // E operator & (E x, E y);
4467 // E operator | (E x, E y);
4468 // E operator ^ (E x, E y);
4471 if ((oper & Operator.ComparisonMask) != 0) {
4472 type = rc.BuiltinTypes.Bool;
4478 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4484 if (ltype == rtype) {
4488 var lifted = new Nullable.LiftedBinaryOperator (this);
4490 lifted.Right = right;
4491 return lifted.Resolve (rc);
4494 if (renum && !ltype.IsNullableType) {
4495 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4500 } else if (lenum && !rtype.IsNullableType) {
4501 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4509 // Now try lifted version of predefined operator
4511 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4512 if (nullable_type != null) {
4513 if (renum && !ltype.IsNullableType) {
4514 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4516 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4519 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4522 if ((oper & Operator.BitwiseMask) != 0)
4526 if ((oper & Operator.BitwiseMask) != 0)
4527 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4529 return CreateLiftedValueTypeResult (rc, rtype);
4533 var lifted = new Nullable.LiftedBinaryOperator (this);
4535 lifted.Right = right;
4536 return lifted.Resolve (rc);
4538 } else if (lenum && !rtype.IsNullableType) {
4539 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4541 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4544 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4547 if ((oper & Operator.BitwiseMask) != 0)
4551 if ((oper & Operator.BitwiseMask) != 0)
4552 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4554 return CreateLiftedValueTypeResult (rc, ltype);
4558 var lifted = new Nullable.LiftedBinaryOperator (this);
4560 lifted.Right = expr;
4561 return lifted.Resolve (rc);
4563 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4564 Nullable.Unwrap unwrap = null;
4565 if (left.IsNull || right.IsNull) {
4566 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4567 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4569 if ((oper & Operator.RelationalMask) != 0)
4570 return CreateLiftedValueTypeResult (rc, rtype);
4572 if ((oper & Operator.BitwiseMask) != 0)
4573 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4576 return CreateLiftedValueTypeResult (rc, left.Type);
4578 // Equality operators are valid between E? and null
4580 unwrap = new Nullable.Unwrap (right);
4582 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4586 if ((oper & Operator.BitwiseMask) != 0)
4591 var lifted = new Nullable.LiftedBinaryOperator (this);
4593 lifted.Right = right;
4594 lifted.UnwrapRight = unwrap;
4595 return lifted.Resolve (rc);
4597 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4598 Nullable.Unwrap unwrap = null;
4599 if (right.IsNull || left.IsNull) {
4600 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4601 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4603 if ((oper & Operator.RelationalMask) != 0)
4604 return CreateLiftedValueTypeResult (rc, ltype);
4606 if ((oper & Operator.BitwiseMask) != 0)
4607 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4610 return CreateLiftedValueTypeResult (rc, right.Type);
4612 // Equality operators are valid between E? and null
4614 unwrap = new Nullable.Unwrap (left);
4616 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4620 if ((oper & Operator.BitwiseMask) != 0)
4625 var lifted = new Nullable.LiftedBinaryOperator (this);
4627 lifted.UnwrapLeft = unwrap;
4628 lifted.Right = expr;
4629 return lifted.Resolve (rc);
4637 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4639 TypeSpec underlying_type;
4640 if (expr.Type.IsNullableType) {
4641 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4643 underlying_type = EnumSpec.GetUnderlyingType (nt);
4645 underlying_type = nt;
4646 } else if (expr.Type.IsEnum) {
4647 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4649 underlying_type = expr.Type;
4652 switch (underlying_type.BuiltinType) {
4653 case BuiltinTypeSpec.Type.SByte:
4654 case BuiltinTypeSpec.Type.Byte:
4655 case BuiltinTypeSpec.Type.Short:
4656 case BuiltinTypeSpec.Type.UShort:
4657 underlying_type = rc.BuiltinTypes.Int;
4661 if (expr.Type.IsNullableType || liftType)
4662 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4664 if (expr.Type == underlying_type)
4667 return EmptyCast.Create (expr, underlying_type);
4670 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4673 // U operator - (E e, E f)
4674 // E operator - (E e, U x) // Internal decomposition operator
4675 // E operator - (U x, E e) // Internal decomposition operator
4677 // E operator + (E e, U x)
4678 // E operator + (U x, E e)
4687 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4693 if (!enum_type.IsNullableType) {
4694 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4696 if (oper == Operator.Subtraction)
4697 expr = ConvertEnumSubtractionResult (rc, expr);
4699 expr = ConvertEnumAdditionalResult (expr, enum_type);
4701 enum_conversion = GetEnumResultCast (expr.Type);
4706 var nullable = rc.Module.PredefinedTypes.Nullable;
4709 // Don't try nullable version when nullable type is undefined
4711 if (!nullable.IsDefined)
4714 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4717 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4719 if (oper == Operator.Subtraction)
4720 expr = ConvertEnumSubtractionResult (rc, expr);
4722 expr = ConvertEnumAdditionalResult (expr, enum_type);
4724 enum_conversion = GetEnumResultCast (expr.Type);
4730 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4732 return EmptyCast.Create (expr, enumType);
4735 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4738 // Enumeration subtraction has different result type based on
4741 TypeSpec result_type;
4742 if (left.Type == right.Type) {
4743 var c = right as EnumConstant;
4744 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4746 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4747 // E which is not what expressions E - 1 or 0 - E return
4749 result_type = left.Type;
4751 result_type = left.Type.IsNullableType ?
4752 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4753 EnumSpec.GetUnderlyingType (left.Type);
4756 if (IsEnumOrNullableEnum (left.Type)) {
4757 result_type = left.Type;
4759 result_type = right.Type;
4762 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4763 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4766 return EmptyCast.Create (expr, result_type);
4769 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4771 if (type.IsNullableType)
4772 type = Nullable.NullableInfo.GetUnderlyingType (type);
4775 type = EnumSpec.GetUnderlyingType (type);
4777 switch (type.BuiltinType) {
4778 case BuiltinTypeSpec.Type.SByte:
4779 return ConvCast.Mode.I4_I1;
4780 case BuiltinTypeSpec.Type.Byte:
4781 return ConvCast.Mode.I4_U1;
4782 case BuiltinTypeSpec.Type.Short:
4783 return ConvCast.Mode.I4_I2;
4784 case BuiltinTypeSpec.Type.UShort:
4785 return ConvCast.Mode.I4_U2;
4792 // Equality operators rules
4794 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4797 type = ec.BuiltinTypes.Bool;
4798 bool no_arg_conv = false;
4800 if (!primitives_only) {
4803 // a, Both operands are reference-type values or the value null
4804 // b, One operand is a value of type T where T is a type-parameter and
4805 // the other operand is the value null. Furthermore T does not have the
4806 // value type constraint
4808 // LAMESPEC: Very confusing details in the specification, basically any
4809 // reference like type-parameter is allowed
4811 var tparam_l = l as TypeParameterSpec;
4812 var tparam_r = r as TypeParameterSpec;
4813 if (tparam_l != null) {
4814 if (right is NullLiteral) {
4815 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4818 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4822 if (!tparam_l.IsReferenceType)
4825 l = tparam_l.GetEffectiveBase ();
4826 left = new BoxedCast (left, l);
4827 } else if (left is NullLiteral && tparam_r == null) {
4828 if (TypeSpec.IsReferenceType (r))
4831 if (r.Kind == MemberKind.InternalCompilerType)
4835 if (tparam_r != null) {
4836 if (left is NullLiteral) {
4837 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4840 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4844 if (!tparam_r.IsReferenceType)
4847 r = tparam_r.GetEffectiveBase ();
4848 right = new BoxedCast (right, r);
4849 } else if (right is NullLiteral) {
4850 if (TypeSpec.IsReferenceType (l))
4853 if (l.Kind == MemberKind.InternalCompilerType)
4858 // LAMESPEC: method groups can be compared when they convert to other side delegate
4861 if (right.eclass == ExprClass.MethodGroup) {
4862 result = Convert.ImplicitConversion (ec, right, l, loc);
4868 } else if (r.IsDelegate && l != r) {
4871 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4872 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4879 no_arg_conv = l == r && !l.IsStruct;
4884 // bool operator != (string a, string b)
4885 // bool operator == (string a, string b)
4887 // bool operator != (Delegate a, Delegate b)
4888 // bool operator == (Delegate a, Delegate b)
4890 // bool operator != (bool a, bool b)
4891 // bool operator == (bool a, bool b)
4893 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4894 // they implement an implicit conversion to any of types above. This does
4895 // not apply when both operands are of same reference type
4897 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4898 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4903 // Now try lifted version of predefined operators
4905 if (no_arg_conv && !l.IsNullableType) {
4907 // Optimizes cases which won't match
4910 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4916 // The == and != operators permit one operand to be a value of a nullable
4917 // type and the other to be the null literal, even if no predefined or user-defined
4918 // operator (in unlifted or lifted form) exists for the operation.
4920 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4921 var lifted = new Nullable.LiftedBinaryOperator (this);
4923 lifted.Right = right;
4924 return lifted.Resolve (ec);
4929 // bool operator != (object a, object b)
4930 // bool operator == (object a, object b)
4932 // An explicit reference conversion exists from the
4933 // type of either operand to the type of the other operand.
4936 // Optimize common path
4938 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4941 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4942 !Convert.ExplicitReferenceConversionExists (r, l))
4945 // Reject allowed explicit conversions like int->object
4946 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4949 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4950 ec.Report.Warning (253, 2, loc,
4951 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4952 l.GetSignatureForError ());
4954 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4955 ec.Report.Warning (252, 2, loc,
4956 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4957 r.GetSignatureForError ());
4963 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4966 // bool operator == (void* x, void* y);
4967 // bool operator != (void* x, void* y);
4968 // bool operator < (void* x, void* y);
4969 // bool operator > (void* x, void* y);
4970 // bool operator <= (void* x, void* y);
4971 // bool operator >= (void* x, void* y);
4973 if ((oper & Operator.ComparisonMask) != 0) {
4976 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4983 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4989 type = ec.BuiltinTypes.Bool;
4993 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4997 // Build-in operators method overloading
4999 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
5001 PredefinedOperator best_operator = null;
5002 TypeSpec l = left.Type;
5003 TypeSpec r = right.Type;
5004 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5006 foreach (PredefinedOperator po in operators) {
5007 if ((po.OperatorsMask & oper_mask) == 0)
5010 if (primitives_only) {
5011 if (!po.IsPrimitiveApplicable (l, r))
5014 if (!po.IsApplicable (ec, left, right))
5018 if (best_operator == null) {
5020 if (primitives_only)
5026 best_operator = po.ResolveBetterOperator (ec, best_operator);
5028 if (best_operator == null) {
5029 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5030 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5037 if (best_operator == null)
5040 return best_operator.ConvertResult (ec, this);
5044 // Optimize & constant expressions with 0 value
5046 Expression OptimizeAndOperation (Expression expr)
5048 Constant rc = right as Constant;
5049 Constant lc = left as Constant;
5050 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5052 // The result is a constant with side-effect
5054 Constant side_effect = rc == null ?
5055 new SideEffectConstant (lc, right, loc) :
5056 new SideEffectConstant (rc, left, loc);
5058 return ReducedExpression.Create (side_effect, expr);
5065 // Value types can be compared with the null literal because of the lifting
5066 // language rules. However the result is always true or false.
5068 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5070 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5071 type = rc.BuiltinTypes.Bool;
5075 // FIXME: Handle side effect constants
5076 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5078 if ((Oper & Operator.EqualityMask) != 0) {
5079 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5080 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5082 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5083 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5090 // Performs user-operator overloading
5092 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5094 Expression oper_expr;
5096 var op = ConvertBinaryToUserOperator (oper);
5098 if (l.IsNullableType)
5099 l = Nullable.NullableInfo.GetUnderlyingType (l);
5101 if (r.IsNullableType)
5102 r = Nullable.NullableInfo.GetUnderlyingType (r);
5104 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5105 IList<MemberSpec> right_operators = null;
5108 right_operators = MemberCache.GetUserOperator (r, op, false);
5109 if (right_operators == null && left_operators == null)
5111 } else if (left_operators == null) {
5115 Arguments args = new Arguments (2);
5116 Argument larg = new Argument (left);
5118 Argument rarg = new Argument (right);
5122 // User-defined operator implementations always take precedence
5123 // over predefined operator implementations
5125 if (left_operators != null && right_operators != null) {
5126 left_operators = CombineUserOperators (left_operators, right_operators);
5127 } else if (right_operators != null) {
5128 left_operators = right_operators;
5131 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5132 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5134 var res = new OverloadResolver (left_operators, restr, loc);
5136 var oper_method = res.ResolveOperator (rc, ref args);
5137 if (oper_method == null) {
5139 // Logical && and || cannot be lifted
5141 if ((oper & Operator.LogicalMask) != 0)
5145 // Apply lifted user operators only for liftable types. Implicit conversion
5146 // to nullable types is not allowed
5148 if (!IsLiftedOperatorApplicable ())
5151 // TODO: Cache the result in module container
5152 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5153 if (lifted_methods == null)
5156 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5158 oper_method = res.ResolveOperator (rc, ref args);
5159 if (oper_method == null)
5162 MethodSpec best_original = null;
5163 foreach (MethodSpec ms in left_operators) {
5164 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5170 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5172 // Expression trees use lifted notation in this case
5174 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5175 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5178 var ptypes = best_original.Parameters.Types;
5180 if (left.IsNull || right.IsNull) {
5182 // The lifted operator produces a null value if one or both operands are null
5184 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5185 type = oper_method.ReturnType;
5186 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5190 // The lifted operator produces the value false if one or both operands are null for
5191 // relational operators.
5193 if ((oper & Operator.RelationalMask) != 0) {
5195 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5196 // because return type is actually bool
5198 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5201 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5202 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5206 type = oper_method.ReturnType;
5207 var lifted = new Nullable.LiftedBinaryOperator (this);
5208 lifted.UserOperator = best_original;
5210 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5211 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5214 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5215 lifted.UnwrapRight = new Nullable.Unwrap (right);
5218 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5219 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5221 return lifted.Resolve (rc);
5224 if ((oper & Operator.LogicalMask) != 0) {
5225 // TODO: CreateExpressionTree is allocated every time
5226 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5227 oper == Operator.LogicalAnd, loc).Resolve (rc);
5229 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5232 this.left = larg.Expr;
5233 this.right = rarg.Expr;
5238 bool IsLiftedOperatorApplicable ()
5240 if (left.Type.IsNullableType) {
5241 if ((oper & Operator.EqualityMask) != 0)
5242 return !right.IsNull;
5247 if (right.Type.IsNullableType) {
5248 if ((oper & Operator.EqualityMask) != 0)
5249 return !left.IsNull;
5254 if (TypeSpec.IsValueType (left.Type))
5255 return right.IsNull;
5257 if (TypeSpec.IsValueType (right.Type))
5263 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5265 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5266 if (nullable_type == null)
5270 // Lifted operators permit predefined and user-defined operators that operate
5271 // on non-nullable value types to also be used with nullable forms of those types.
5272 // Lifted operators are constructed from predefined and user-defined operators
5273 // that meet certain requirements
5275 List<MemberSpec> lifted = null;
5276 foreach (MethodSpec oper in operators) {
5278 if ((Oper & Operator.ComparisonMask) != 0) {
5280 // Result type must be of type bool for lifted comparison operators
5282 rt = oper.ReturnType;
5283 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5286 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5292 var ptypes = oper.Parameters.Types;
5293 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5297 // LAMESPEC: I am not sure why but for equality operators to be lifted
5298 // both types have to match
5300 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5304 lifted = new List<MemberSpec> ();
5307 // The lifted form is constructed by adding a single ? modifier to each operand and
5308 // result type except for comparison operators where return type is bool
5311 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5313 var parameters = ParametersCompiled.CreateFullyResolved (
5314 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5315 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5317 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5318 rt, parameters, oper.Modifiers);
5320 lifted.Add (lifted_op);
5327 // Merge two sets of user operators into one, they are mostly distinguish
5328 // except when they share base type and it contains an operator
5330 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5332 var combined = new List<MemberSpec> (left.Count + right.Count);
5333 combined.AddRange (left);
5334 foreach (var r in right) {
5336 foreach (var l in left) {
5337 if (l.DeclaringType == r.DeclaringType) {
5350 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5352 if (c is IntegralConstant || c is CharConstant) {
5354 c.ConvertExplicitly (true, type);
5355 } catch (OverflowException) {
5356 ec.Report.Warning (652, 2, loc,
5357 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5358 type.GetSignatureForError ());
5364 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5365 /// context of a conditional bool expression. This function will return
5366 /// false if it is was possible to use EmitBranchable, or true if it was.
5368 /// The expression's code is generated, and we will generate a branch to `target'
5369 /// if the resulting expression value is equal to isTrue
5371 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5373 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5374 left = left.EmitToField (ec);
5376 if ((oper & Operator.LogicalMask) == 0) {
5377 right = right.EmitToField (ec);
5382 // This is more complicated than it looks, but its just to avoid
5383 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5384 // but on top of that we want for == and != to use a special path
5385 // if we are comparing against null
5387 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5388 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5391 // put the constant on the rhs, for simplicity
5393 if (left is Constant) {
5394 Expression swap = right;
5400 // brtrue/brfalse works with native int only
5402 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5403 left.EmitBranchable (ec, target, my_on_true);
5406 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5407 // right is a boolean, and it's not 'false' => it is 'true'
5408 left.EmitBranchable (ec, target, !my_on_true);
5412 } else if (oper == Operator.LogicalAnd) {
5415 Label tests_end = ec.DefineLabel ();
5417 left.EmitBranchable (ec, tests_end, false);
5418 right.EmitBranchable (ec, target, true);
5419 ec.MarkLabel (tests_end);
5422 // This optimizes code like this
5423 // if (true && i > 4)
5425 if (!(left is Constant))
5426 left.EmitBranchable (ec, target, false);
5428 if (!(right is Constant))
5429 right.EmitBranchable (ec, target, false);
5434 } else if (oper == Operator.LogicalOr){
5436 left.EmitBranchable (ec, target, true);
5437 right.EmitBranchable (ec, target, true);
5440 Label tests_end = ec.DefineLabel ();
5441 left.EmitBranchable (ec, tests_end, true);
5442 right.EmitBranchable (ec, target, false);
5443 ec.MarkLabel (tests_end);
5448 } else if ((oper & Operator.ComparisonMask) == 0) {
5449 base.EmitBranchable (ec, target, on_true);
5456 TypeSpec t = left.Type;
5457 bool is_float = IsFloat (t);
5458 bool is_unsigned = is_float || IsUnsigned (t);
5461 case Operator.Equality:
5463 ec.Emit (OpCodes.Beq, target);
5465 ec.Emit (OpCodes.Bne_Un, target);
5468 case Operator.Inequality:
5470 ec.Emit (OpCodes.Bne_Un, target);
5472 ec.Emit (OpCodes.Beq, target);
5475 case Operator.LessThan:
5477 if (is_unsigned && !is_float)
5478 ec.Emit (OpCodes.Blt_Un, target);
5480 ec.Emit (OpCodes.Blt, target);
5483 ec.Emit (OpCodes.Bge_Un, target);
5485 ec.Emit (OpCodes.Bge, target);
5488 case Operator.GreaterThan:
5490 if (is_unsigned && !is_float)
5491 ec.Emit (OpCodes.Bgt_Un, target);
5493 ec.Emit (OpCodes.Bgt, target);
5496 ec.Emit (OpCodes.Ble_Un, target);
5498 ec.Emit (OpCodes.Ble, target);
5501 case Operator.LessThanOrEqual:
5503 if (is_unsigned && !is_float)
5504 ec.Emit (OpCodes.Ble_Un, target);
5506 ec.Emit (OpCodes.Ble, target);
5509 ec.Emit (OpCodes.Bgt_Un, target);
5511 ec.Emit (OpCodes.Bgt, target);
5515 case Operator.GreaterThanOrEqual:
5517 if (is_unsigned && !is_float)
5518 ec.Emit (OpCodes.Bge_Un, target);
5520 ec.Emit (OpCodes.Bge, target);
5523 ec.Emit (OpCodes.Blt_Un, target);
5525 ec.Emit (OpCodes.Blt, target);
5528 throw new InternalErrorException (oper.ToString ());
5532 public override void Emit (EmitContext ec)
5534 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5535 left = left.EmitToField (ec);
5537 if ((oper & Operator.LogicalMask) == 0) {
5538 right = right.EmitToField (ec);
5543 // Handle short-circuit operators differently
5546 if ((oper & Operator.LogicalMask) != 0) {
5547 Label load_result = ec.DefineLabel ();
5548 Label end = ec.DefineLabel ();
5550 bool is_or = oper == Operator.LogicalOr;
5551 left.EmitBranchable (ec, load_result, is_or);
5553 ec.Emit (OpCodes.Br_S, end);
5555 ec.MarkLabel (load_result);
5556 ec.EmitInt (is_or ? 1 : 0);
5562 // Optimize zero-based operations which cannot be optimized at expression level
5564 if (oper == Operator.Subtraction) {
5565 var lc = left as IntegralConstant;
5566 if (lc != null && lc.IsDefaultValue) {
5568 ec.Emit (OpCodes.Neg);
5573 EmitOperator (ec, left, right);
5576 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5581 EmitOperatorOpcode (ec, oper, left.Type, right);
5584 // Emit result enumerable conversion this way because it's quite complicated get it
5585 // to resolved tree because expression tree cannot see it.
5587 if (enum_conversion != 0)
5588 ConvCast.Emit (ec, enum_conversion);
5591 public override void EmitSideEffect (EmitContext ec)
5593 if ((oper & Operator.LogicalMask) != 0 ||
5594 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5595 base.EmitSideEffect (ec);
5597 left.EmitSideEffect (ec);
5598 right.EmitSideEffect (ec);
5602 public override Expression EmitToField (EmitContext ec)
5604 if ((oper & Operator.LogicalMask) == 0) {
5605 var await_expr = left as Await;
5606 if (await_expr != null && right.IsSideEffectFree) {
5607 await_expr.Statement.EmitPrologue (ec);
5608 left = await_expr.Statement.GetResultExpression (ec);
5612 await_expr = right as Await;
5613 if (await_expr != null && left.IsSideEffectFree) {
5614 await_expr.Statement.EmitPrologue (ec);
5615 right = await_expr.Statement.GetResultExpression (ec);
5620 return base.EmitToField (ec);
5623 protected override void CloneTo (CloneContext clonectx, Expression t)
5625 Binary target = (Binary) t;
5627 target.left = left.Clone (clonectx);
5628 target.right = right.Clone (clonectx);
5631 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5633 Arguments binder_args = new Arguments (4);
5635 MemberAccess sle = new MemberAccess (new MemberAccess (
5636 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5638 CSharpBinderFlags flags = 0;
5639 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5640 flags = CSharpBinderFlags.CheckedContext;
5642 if ((oper & Operator.LogicalMask) != 0)
5643 flags |= CSharpBinderFlags.BinaryOperationLogical;
5645 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5646 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5647 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5648 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5650 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5653 public override Expression CreateExpressionTree (ResolveContext ec)
5655 return CreateExpressionTree (ec, null);
5658 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5661 bool lift_arg = false;
5664 case Operator.Addition:
5665 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5666 method_name = "AddChecked";
5668 method_name = "Add";
5670 case Operator.BitwiseAnd:
5671 method_name = "And";
5673 case Operator.BitwiseOr:
5676 case Operator.Division:
5677 method_name = "Divide";
5679 case Operator.Equality:
5680 method_name = "Equal";
5683 case Operator.ExclusiveOr:
5684 method_name = "ExclusiveOr";
5686 case Operator.GreaterThan:
5687 method_name = "GreaterThan";
5690 case Operator.GreaterThanOrEqual:
5691 method_name = "GreaterThanOrEqual";
5694 case Operator.Inequality:
5695 method_name = "NotEqual";
5698 case Operator.LeftShift:
5699 method_name = "LeftShift";
5701 case Operator.LessThan:
5702 method_name = "LessThan";
5705 case Operator.LessThanOrEqual:
5706 method_name = "LessThanOrEqual";
5709 case Operator.LogicalAnd:
5710 method_name = "AndAlso";
5712 case Operator.LogicalOr:
5713 method_name = "OrElse";
5715 case Operator.Modulus:
5716 method_name = "Modulo";
5718 case Operator.Multiply:
5719 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5720 method_name = "MultiplyChecked";
5722 method_name = "Multiply";
5724 case Operator.RightShift:
5725 method_name = "RightShift";
5727 case Operator.Subtraction:
5728 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5729 method_name = "SubtractChecked";
5731 method_name = "Subtract";
5735 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5738 Arguments args = new Arguments (2);
5739 args.Add (new Argument (left.CreateExpressionTree (ec)));
5740 args.Add (new Argument (right.CreateExpressionTree (ec)));
5741 if (method != null) {
5743 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5745 args.Add (new Argument (method));
5748 return CreateExpressionFactoryCall (ec, method_name, args);
5751 public override object Accept (StructuralVisitor visitor)
5753 return visitor.Visit (this);
5759 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5760 // b, c, d... may be strings or objects.
5762 public class StringConcat : Expression
5764 Arguments arguments;
5766 StringConcat (Location loc)
5769 arguments = new Arguments (2);
5772 public override bool ContainsEmitWithAwait ()
5774 return arguments.ContainsEmitWithAwait ();
5777 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5779 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5780 throw new ArgumentException ();
5782 var s = new StringConcat (loc);
5783 s.type = rc.BuiltinTypes.String;
5784 s.eclass = ExprClass.Value;
5786 s.Append (rc, left);
5787 s.Append (rc, right);
5791 public override Expression CreateExpressionTree (ResolveContext ec)
5793 Argument arg = arguments [0];
5794 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5798 // Creates nested calls tree from an array of arguments used for IL emit
5800 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5802 Arguments concat_args = new Arguments (2);
5803 Arguments add_args = new Arguments (3);
5805 concat_args.Add (left);
5806 add_args.Add (new Argument (left_etree));
5808 concat_args.Add (arguments [pos]);
5809 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5811 var methods = GetConcatMethodCandidates ();
5812 if (methods == null)
5815 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5816 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5820 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5822 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5823 if (++pos == arguments.Count)
5826 left = new Argument (new EmptyExpression (method.ReturnType));
5827 return CreateExpressionAddCall (ec, left, expr, pos);
5830 protected override Expression DoResolve (ResolveContext ec)
5835 void Append (ResolveContext rc, Expression operand)
5840 StringConstant sc = operand as StringConstant;
5842 if (arguments.Count != 0) {
5843 Argument last_argument = arguments [arguments.Count - 1];
5844 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5845 if (last_expr_constant != null) {
5846 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5852 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5854 StringConcat concat_oper = operand as StringConcat;
5855 if (concat_oper != null) {
5856 arguments.AddRange (concat_oper.arguments);
5861 arguments.Add (new Argument (operand));
5864 IList<MemberSpec> GetConcatMethodCandidates ()
5866 return MemberCache.FindMembers (type, "Concat", true);
5869 public override void Emit (EmitContext ec)
5871 // Optimize by removing any extra null arguments, they are no-op
5872 for (int i = 0; i < arguments.Count; ++i) {
5873 if (arguments[i].Expr is NullConstant)
5874 arguments.RemoveAt (i--);
5877 var members = GetConcatMethodCandidates ();
5878 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5879 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5880 if (method != null) {
5881 var call = new CallEmitter ();
5882 call.EmitPredefined (ec, method, arguments, false);
5886 public override void FlowAnalysis (FlowAnalysisContext fc)
5888 arguments.FlowAnalysis (fc);
5891 public override SLE.Expression MakeExpression (BuilderContext ctx)
5893 if (arguments.Count != 2)
5894 throw new NotImplementedException ("arguments.Count != 2");
5896 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5897 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5902 // User-defined conditional logical operator
5904 public class ConditionalLogicalOperator : UserOperatorCall
5906 readonly bool is_and;
5907 Expression oper_expr;
5909 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5910 : base (oper, arguments, expr_tree, loc)
5912 this.is_and = is_and;
5913 eclass = ExprClass.Unresolved;
5916 protected override Expression DoResolve (ResolveContext ec)
5918 AParametersCollection pd = oper.Parameters;
5919 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5920 ec.Report.Error (217, loc,
5921 "A user-defined operator `{0}' must have each parameter type and return type of the same type in order to be applicable as a short circuit operator",
5922 oper.GetSignatureForError ());
5926 Expression left_dup = new EmptyExpression (type);
5927 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5928 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5929 if (op_true == null || op_false == null) {
5930 ec.Report.Error (218, loc,
5931 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5932 type.GetSignatureForError (), oper.GetSignatureForError ());
5936 oper_expr = is_and ? op_false : op_true;
5937 eclass = ExprClass.Value;
5941 public override void Emit (EmitContext ec)
5943 Label end_target = ec.DefineLabel ();
5946 // Emit and duplicate left argument
5948 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5949 if (right_contains_await) {
5950 arguments[0] = arguments[0].EmitToField (ec, false);
5951 arguments[0].Expr.Emit (ec);
5953 arguments[0].Expr.Emit (ec);
5954 ec.Emit (OpCodes.Dup);
5955 arguments.RemoveAt (0);
5958 oper_expr.EmitBranchable (ec, end_target, true);
5962 if (right_contains_await) {
5964 // Special handling when right expression contains await and left argument
5965 // could not be left on stack before logical branch
5967 Label skip_left_load = ec.DefineLabel ();
5968 ec.Emit (OpCodes.Br_S, skip_left_load);
5969 ec.MarkLabel (end_target);
5970 arguments[0].Expr.Emit (ec);
5971 ec.MarkLabel (skip_left_load);
5973 ec.MarkLabel (end_target);
5978 public class PointerArithmetic : Expression {
5979 Expression left, right;
5980 readonly Binary.Operator op;
5983 // We assume that `l' is always a pointer
5985 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5994 public override bool ContainsEmitWithAwait ()
5996 throw new NotImplementedException ();
5999 public override Expression CreateExpressionTree (ResolveContext ec)
6001 Error_PointerInsideExpressionTree (ec);
6005 protected override Expression DoResolve (ResolveContext ec)
6007 eclass = ExprClass.Variable;
6009 var pc = left.Type as PointerContainer;
6010 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6011 Error_VoidPointerOperation (ec);
6018 public override void Emit (EmitContext ec)
6020 TypeSpec op_type = left.Type;
6022 // It must be either array or fixed buffer
6024 if (TypeManager.HasElementType (op_type)) {
6025 element = TypeManager.GetElementType (op_type);
6027 FieldExpr fe = left as FieldExpr;
6029 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6034 int size = BuiltinTypeSpec.GetSize(element);
6035 TypeSpec rtype = right.Type;
6037 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6039 // handle (pointer - pointer)
6043 ec.Emit (OpCodes.Sub);
6047 ec.Emit (OpCodes.Sizeof, element);
6050 ec.Emit (OpCodes.Div);
6052 ec.Emit (OpCodes.Conv_I8);
6055 // handle + and - on (pointer op int)
6057 Constant left_const = left as Constant;
6058 if (left_const != null) {
6060 // Optimize ((T*)null) pointer operations
6062 if (left_const.IsDefaultValue) {
6063 left = EmptyExpression.Null;
6071 var right_const = right as Constant;
6072 if (right_const != null) {
6074 // Optimize 0-based arithmetic
6076 if (right_const.IsDefaultValue)
6080 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6082 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6084 // TODO: Should be the checks resolve context sensitive?
6085 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6086 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6092 if (right_const == null) {
6093 switch (rtype.BuiltinType) {
6094 case BuiltinTypeSpec.Type.SByte:
6095 case BuiltinTypeSpec.Type.Byte:
6096 case BuiltinTypeSpec.Type.Short:
6097 case BuiltinTypeSpec.Type.UShort:
6098 case BuiltinTypeSpec.Type.Int:
6099 ec.Emit (OpCodes.Conv_I);
6101 case BuiltinTypeSpec.Type.UInt:
6102 ec.Emit (OpCodes.Conv_U);
6107 if (right_const == null && size != 1){
6109 ec.Emit (OpCodes.Sizeof, element);
6112 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6113 ec.Emit (OpCodes.Conv_I8);
6115 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6118 if (left_const == null) {
6119 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6120 ec.Emit (OpCodes.Conv_I);
6121 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6122 ec.Emit (OpCodes.Conv_U);
6124 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6131 // A boolean-expression is an expression that yields a result
6134 public class BooleanExpression : ShimExpression
6136 public BooleanExpression (Expression expr)
6139 this.loc = expr.Location;
6142 public override Expression CreateExpressionTree (ResolveContext ec)
6144 // TODO: We should emit IsTrue (v4) instead of direct user operator
6145 // call but that would break csc compatibility
6146 return base.CreateExpressionTree (ec);
6149 protected override Expression DoResolve (ResolveContext ec)
6151 // A boolean-expression is required to be of a type
6152 // that can be implicitly converted to bool or of
6153 // a type that implements operator true
6155 expr = expr.Resolve (ec);
6159 Assign ass = expr as Assign;
6160 if (ass != null && ass.Source is Constant) {
6161 ec.Report.Warning (665, 3, loc,
6162 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6165 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6168 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6169 Arguments args = new Arguments (1);
6170 args.Add (new Argument (expr));
6171 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6174 type = ec.BuiltinTypes.Bool;
6175 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6176 if (converted != null)
6180 // If no implicit conversion to bool exists, try using `operator true'
6182 converted = GetOperatorTrue (ec, expr, loc);
6183 if (converted == null) {
6184 expr.Error_ValueCannotBeConverted (ec, type, false);
6191 public override object Accept (StructuralVisitor visitor)
6193 return visitor.Visit (this);
6197 public class BooleanExpressionFalse : Unary
6199 public BooleanExpressionFalse (Expression expr)
6200 : base (Operator.LogicalNot, expr, expr.Location)
6204 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6206 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6211 /// Implements the ternary conditional operator (?:)
6213 public class Conditional : Expression {
6214 Expression expr, true_expr, false_expr;
6216 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6219 this.true_expr = true_expr;
6220 this.false_expr = false_expr;
6226 public Expression Expr {
6232 public Expression TrueExpr {
6238 public Expression FalseExpr {
6246 public override bool ContainsEmitWithAwait ()
6248 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6251 public override Expression CreateExpressionTree (ResolveContext ec)
6253 Arguments args = new Arguments (3);
6254 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6255 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6256 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6257 return CreateExpressionFactoryCall (ec, "Condition", args);
6260 protected override Expression DoResolve (ResolveContext ec)
6262 expr = expr.Resolve (ec);
6263 true_expr = true_expr.Resolve (ec);
6264 false_expr = false_expr.Resolve (ec);
6266 if (true_expr == null || false_expr == null || expr == null)
6269 eclass = ExprClass.Value;
6270 TypeSpec true_type = true_expr.Type;
6271 TypeSpec false_type = false_expr.Type;
6275 // First, if an implicit conversion exists from true_expr
6276 // to false_expr, then the result type is of type false_expr.Type
6278 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6279 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6280 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6282 // Check if both can convert implicitly to each other's type
6286 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6287 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6289 // LAMESPEC: There seems to be hardcoded promotition to int type when
6290 // both sides are numeric constants and one side is int constant and
6291 // other side is numeric constant convertible to int.
6293 // var res = condition ? (short)1 : 1;
6295 // Type of res is int even if according to the spec the conversion is
6296 // ambiguous because 1 literal can be converted to short.
6298 if (conv_false_expr != null) {
6299 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6301 conv_false_expr = null;
6302 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6303 conv_false_expr = null;
6307 if (conv_false_expr != null) {
6308 ec.Report.Error (172, true_expr.Location,
6309 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6310 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6315 if (true_expr.Type != type)
6316 true_expr = EmptyCast.Create (true_expr, type);
6317 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6320 if (false_type != InternalType.ErrorType) {
6321 ec.Report.Error (173, true_expr.Location,
6322 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6323 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6329 Constant c = expr as Constant;
6331 bool is_false = c.IsDefaultValue;
6334 // Don't issue the warning for constant expressions
6336 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6337 // CSC: Missing warning
6338 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6341 return ReducedExpression.Create (
6342 is_false ? false_expr : true_expr, this,
6343 false_expr is Constant && true_expr is Constant).Resolve (ec);
6349 public override void Emit (EmitContext ec)
6351 Label false_target = ec.DefineLabel ();
6352 Label end_target = ec.DefineLabel ();
6354 expr.EmitBranchable (ec, false_target, false);
6355 true_expr.Emit (ec);
6358 // Verifier doesn't support interface merging. When there are two types on
6359 // the stack without common type hint and the common type is an interface.
6360 // Use temporary local to give verifier hint on what type to unify the stack
6362 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6363 var temp = ec.GetTemporaryLocal (type);
6364 ec.Emit (OpCodes.Stloc, temp);
6365 ec.Emit (OpCodes.Ldloc, temp);
6366 ec.FreeTemporaryLocal (temp, type);
6369 ec.Emit (OpCodes.Br, end_target);
6370 ec.MarkLabel (false_target);
6371 false_expr.Emit (ec);
6372 ec.MarkLabel (end_target);
6375 public override void FlowAnalysis (FlowAnalysisContext fc)
6377 expr.FlowAnalysisConditional (fc);
6378 var expr_true = fc.DefiniteAssignmentOnTrue;
6379 var expr_false = fc.DefiniteAssignmentOnFalse;
6381 fc.BranchDefiniteAssignment (expr_true);
6382 true_expr.FlowAnalysis (fc);
6383 var true_fc = fc.DefiniteAssignment;
6385 fc.BranchDefiniteAssignment (expr_false);
6386 false_expr.FlowAnalysis (fc);
6388 fc.DefiniteAssignment &= true_fc;
6391 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6393 expr.FlowAnalysisConditional (fc);
6394 var expr_true = fc.DefiniteAssignmentOnTrue;
6395 var expr_false = fc.DefiniteAssignmentOnFalse;
6397 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6398 true_expr.FlowAnalysisConditional (fc);
6399 var true_fc = fc.DefiniteAssignment;
6400 var true_da_true = fc.DefiniteAssignmentOnTrue;
6401 var true_da_false = fc.DefiniteAssignmentOnFalse;
6403 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6404 false_expr.FlowAnalysisConditional (fc);
6406 fc.DefiniteAssignment &= true_fc;
6407 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6408 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6411 protected override void CloneTo (CloneContext clonectx, Expression t)
6413 Conditional target = (Conditional) t;
6415 target.expr = expr.Clone (clonectx);
6416 target.true_expr = true_expr.Clone (clonectx);
6417 target.false_expr = false_expr.Clone (clonectx);
6421 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6423 LocalTemporary temp;
6426 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6427 public abstract void SetHasAddressTaken ();
6429 public abstract bool IsLockedByStatement { get; set; }
6431 public abstract bool IsFixed { get; }
6432 public abstract bool IsRef { get; }
6433 public abstract string Name { get; }
6436 // Variable IL data, it has to be protected to encapsulate hoisted variables
6438 protected abstract ILocalVariable Variable { get; }
6441 // Variable flow-analysis data
6443 public abstract VariableInfo VariableInfo { get; }
6446 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6448 HoistedVariable hv = GetHoistedVariable (ec);
6450 hv.AddressOf (ec, mode);
6454 Variable.EmitAddressOf (ec);
6457 public override bool ContainsEmitWithAwait ()
6462 public override Expression CreateExpressionTree (ResolveContext ec)
6464 HoistedVariable hv = GetHoistedVariable (ec);
6466 return hv.CreateExpressionTree ();
6468 Arguments arg = new Arguments (1);
6469 arg.Add (new Argument (this));
6470 return CreateExpressionFactoryCall (ec, "Constant", arg);
6473 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6475 if (IsLockedByStatement) {
6476 rc.Report.Warning (728, 2, loc,
6477 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6484 public override void Emit (EmitContext ec)
6489 public override void EmitSideEffect (EmitContext ec)
6495 // This method is used by parameters that are references, that are
6496 // being passed as references: we only want to pass the pointer (that
6497 // is already stored in the parameter, not the address of the pointer,
6498 // and not the value of the variable).
6500 public void EmitLoad (EmitContext ec)
6505 public void Emit (EmitContext ec, bool leave_copy)
6507 HoistedVariable hv = GetHoistedVariable (ec);
6509 hv.Emit (ec, leave_copy);
6517 // If we are a reference, we loaded on the stack a pointer
6518 // Now lets load the real value
6520 ec.EmitLoadFromPtr (type);
6524 ec.Emit (OpCodes.Dup);
6527 temp = new LocalTemporary (Type);
6533 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6534 bool prepare_for_load)
6536 HoistedVariable hv = GetHoistedVariable (ec);
6538 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6542 New n_source = source as New;
6543 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6544 if (!n_source.Emit (ec, this)) {
6548 ec.EmitLoadFromPtr (type);
6560 ec.Emit (OpCodes.Dup);
6562 temp = new LocalTemporary (Type);
6568 ec.EmitStoreFromPtr (type);
6570 Variable.EmitAssign (ec);
6578 public override Expression EmitToField (EmitContext ec)
6580 HoistedVariable hv = GetHoistedVariable (ec);
6582 return hv.EmitToField (ec);
6585 return base.EmitToField (ec);
6588 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6590 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6593 public HoistedVariable GetHoistedVariable (EmitContext ec)
6595 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6598 public override string GetSignatureForError ()
6603 public bool IsHoisted {
6604 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6609 // Resolved reference to a local variable
6611 public class LocalVariableReference : VariableReference
6613 public LocalVariable local_info;
6615 public LocalVariableReference (LocalVariable li, Location l)
6617 this.local_info = li;
6621 public override VariableInfo VariableInfo {
6622 get { return local_info.VariableInfo; }
6625 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6627 return local_info.HoistedVariant;
6633 // A local variable is always fixed
6635 public override bool IsFixed {
6641 public override bool IsLockedByStatement {
6643 return local_info.IsLocked;
6646 local_info.IsLocked = value;
6650 public override bool IsRef {
6651 get { return false; }
6654 public override string Name {
6655 get { return local_info.Name; }
6660 public override void FlowAnalysis (FlowAnalysisContext fc)
6662 VariableInfo variable_info = VariableInfo;
6663 if (variable_info == null)
6666 if (fc.IsDefinitelyAssigned (variable_info))
6669 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6670 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6673 public override void SetHasAddressTaken ()
6675 local_info.SetHasAddressTaken ();
6678 void DoResolveBase (ResolveContext ec)
6680 eclass = ExprClass.Variable;
6681 type = local_info.Type;
6684 // If we are referencing a variable from the external block
6685 // flag it for capturing
6687 if (ec.MustCaptureVariable (local_info)) {
6688 if (local_info.AddressTaken) {
6689 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6690 } else if (local_info.IsFixed) {
6691 ec.Report.Error (1764, loc,
6692 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6693 GetSignatureForError ());
6696 if (ec.IsVariableCapturingRequired) {
6697 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6698 storey.CaptureLocalVariable (ec, local_info);
6703 protected override Expression DoResolve (ResolveContext ec)
6705 local_info.SetIsUsed ();
6709 if (local_info.Type == InternalType.VarOutType) {
6710 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6711 GetSignatureForError ());
6713 type = InternalType.ErrorType;
6719 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6722 // Don't be too pedantic when variable is used as out param or for some broken code
6723 // which uses property/indexer access to run some initialization
6725 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6726 local_info.SetIsUsed ();
6728 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6729 if (rhs == EmptyExpression.LValueMemberAccess) {
6730 // CS1654 already reported
6734 if (rhs == EmptyExpression.OutAccess) {
6735 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6736 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6737 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6738 } else if (rhs == EmptyExpression.UnaryAddress) {
6739 code = 459; msg = "Cannot take the address of {1} `{0}'";
6741 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6743 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6747 if (eclass == ExprClass.Unresolved)
6750 return base.DoResolveLValue (ec, rhs);
6753 public override int GetHashCode ()
6755 return local_info.GetHashCode ();
6758 public override bool Equals (object obj)
6760 LocalVariableReference lvr = obj as LocalVariableReference;
6764 return local_info == lvr.local_info;
6767 protected override ILocalVariable Variable {
6768 get { return local_info; }
6771 public override string ToString ()
6773 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6776 protected override void CloneTo (CloneContext clonectx, Expression t)
6783 /// This represents a reference to a parameter in the intermediate
6786 public class ParameterReference : VariableReference
6788 protected ParametersBlock.ParameterInfo pi;
6790 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6798 public override bool IsLockedByStatement {
6803 pi.IsLocked = value;
6807 public override bool IsRef {
6808 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6811 bool HasOutModifier {
6812 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6815 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6817 return pi.Parameter.HoistedVariant;
6821 // A ref or out parameter is classified as a moveable variable, even
6822 // if the argument given for the parameter is a fixed variable
6824 public override bool IsFixed {
6825 get { return !IsRef; }
6828 public override string Name {
6829 get { return Parameter.Name; }
6832 public Parameter Parameter {
6833 get { return pi.Parameter; }
6836 public override VariableInfo VariableInfo {
6837 get { return pi.VariableInfo; }
6840 protected override ILocalVariable Variable {
6841 get { return Parameter; }
6846 public override void AddressOf (EmitContext ec, AddressOp mode)
6849 // ParameterReferences might already be a reference
6856 base.AddressOf (ec, mode);
6859 public override void SetHasAddressTaken ()
6861 Parameter.HasAddressTaken = true;
6864 bool DoResolveBase (ResolveContext ec)
6866 if (eclass != ExprClass.Unresolved)
6869 type = pi.ParameterType;
6870 eclass = ExprClass.Variable;
6873 // If we are referencing a parameter from the external block
6874 // flag it for capturing
6876 if (ec.MustCaptureVariable (pi)) {
6877 if (Parameter.HasAddressTaken)
6878 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6881 ec.Report.Error (1628, loc,
6882 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6883 Name, ec.CurrentAnonymousMethod.ContainerType);
6886 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6887 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6888 storey.CaptureParameter (ec, pi, this);
6895 public override int GetHashCode ()
6897 return Name.GetHashCode ();
6900 public override bool Equals (object obj)
6902 ParameterReference pr = obj as ParameterReference;
6906 return Name == pr.Name;
6909 protected override void CloneTo (CloneContext clonectx, Expression target)
6915 public override Expression CreateExpressionTree (ResolveContext ec)
6917 HoistedVariable hv = GetHoistedVariable (ec);
6919 return hv.CreateExpressionTree ();
6921 return Parameter.ExpressionTreeVariableReference ();
6924 protected override Expression DoResolve (ResolveContext ec)
6926 if (!DoResolveBase (ec))
6932 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6934 if (!DoResolveBase (ec))
6937 if (Parameter.HoistedVariant != null)
6938 Parameter.HoistedVariant.IsAssigned = true;
6940 return base.DoResolveLValue (ec, right_side);
6943 public override void FlowAnalysis (FlowAnalysisContext fc)
6945 VariableInfo variable_info = VariableInfo;
6946 if (variable_info == null)
6949 if (fc.IsDefinitelyAssigned (variable_info))
6952 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6953 fc.SetVariableAssigned (variable_info);
6958 /// Invocation of methods or delegates.
6960 public class Invocation : ExpressionStatement
6962 public class Predefined : Invocation
6964 public Predefined (MethodGroupExpr expr, Arguments arguments)
6965 : base (expr, arguments)
6970 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6972 mg.BestCandidate.CheckObsoleteness (rc, loc);
6978 protected Arguments arguments;
6979 protected Expression expr;
6980 protected MethodGroupExpr mg;
6981 bool conditional_access_receiver;
6983 public Invocation (Expression expr, Arguments arguments)
6986 this.arguments = arguments;
6988 loc = expr.Location;
6993 public Arguments Arguments {
6999 public Expression Exp {
7005 public MethodGroupExpr MethodGroup {
7011 public override Location StartLocation {
7013 return expr.StartLocation;
7019 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7021 if (MethodGroup == null)
7024 var candidate = MethodGroup.BestCandidate;
7025 if (candidate == null || !(candidate.IsStatic || Exp is This))
7028 var args_count = arguments == null ? 0 : arguments.Count;
7029 if (args_count != body.Parameters.Count)
7032 var lambda_parameters = body.Block.Parameters.FixedParameters;
7033 for (int i = 0; i < args_count; ++i) {
7034 var pr = arguments[i].Expr as ParameterReference;
7038 if (lambda_parameters[i] != pr.Parameter)
7041 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7045 var emg = MethodGroup as ExtensionMethodGroupExpr;
7047 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7048 if (candidate.IsGeneric) {
7049 var targs = new TypeExpression [candidate.Arity];
7050 for (int i = 0; i < targs.Length; ++i) {
7051 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7054 mg.SetTypeArguments (null, new TypeArguments (targs));
7063 protected override void CloneTo (CloneContext clonectx, Expression t)
7065 Invocation target = (Invocation) t;
7067 if (arguments != null)
7068 target.arguments = arguments.Clone (clonectx);
7070 target.expr = expr.Clone (clonectx);
7073 public override bool ContainsEmitWithAwait ()
7075 if (arguments != null && arguments.ContainsEmitWithAwait ())
7078 return mg.ContainsEmitWithAwait ();
7081 public override Expression CreateExpressionTree (ResolveContext ec)
7083 Expression instance = mg.IsInstance ?
7084 mg.InstanceExpression.CreateExpressionTree (ec) :
7085 new NullLiteral (loc);
7087 var args = Arguments.CreateForExpressionTree (ec, arguments,
7089 mg.CreateExpressionTree (ec));
7091 return CreateExpressionFactoryCall (ec, "Call", args);
7094 void ResolveConditionalAccessReceiver (ResolveContext rc)
7096 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7097 conditional_access_receiver = true;
7101 bool statement_resolve;
7102 public override ExpressionStatement ResolveStatement (BlockContext bc)
7104 statement_resolve = true;
7105 var es = base.ResolveStatement (bc);
7106 statement_resolve = false;
7111 protected override Expression DoResolve (ResolveContext rc)
7113 ResolveConditionalAccessReceiver (rc);
7114 return DoResolveInvocation (rc);
7117 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7119 var sn = expr as SimpleName;
7120 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
7121 throw new NotImplementedException ("var deconstruct");
7124 return base.DoResolveLValue (rc, right_side);
7127 Expression DoResolveInvocation (ResolveContext ec)
7129 Expression member_expr;
7130 var atn = expr as ATypeNameExpression;
7132 var flags = default (ResolveContext.FlagsHandle);
7133 if (conditional_access_receiver)
7134 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7137 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7138 if (member_expr != null) {
7139 var name_of = member_expr as NameOf;
7140 if (name_of != null) {
7141 return name_of.ResolveOverload (ec, arguments);
7144 member_expr = member_expr.Resolve (ec);
7147 member_expr = expr.Resolve (ec);
7150 if (conditional_access_receiver)
7153 if (member_expr == null)
7157 // Next, evaluate all the expressions in the argument list
7159 bool dynamic_arg = false;
7160 if (arguments != null) {
7161 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7162 arguments.Resolve (ec, out dynamic_arg);
7166 TypeSpec expr_type = member_expr.Type;
7167 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7168 return DoResolveDynamic (ec, member_expr);
7170 mg = member_expr as MethodGroupExpr;
7171 Expression invoke = null;
7174 if (expr_type != null && expr_type.IsDelegate) {
7175 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7176 invoke = invoke.Resolve (ec);
7177 if (invoke == null || !dynamic_arg)
7180 if (member_expr is RuntimeValueExpression) {
7181 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7182 member_expr.Type.GetSignatureForError ());
7186 MemberExpr me = member_expr as MemberExpr;
7188 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7192 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7193 member_expr.GetSignatureForError ());
7198 if (invoke == null) {
7199 mg = DoResolveOverload (ec);
7205 return DoResolveDynamic (ec, member_expr);
7207 var method = mg.BestCandidate;
7208 type = mg.BestCandidateReturnType;
7209 if (conditional_access_receiver && !statement_resolve)
7210 type = LiftMemberType (ec, type);
7212 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7214 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7216 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7220 IsSpecialMethodInvocation (ec, method, loc);
7222 eclass = ExprClass.Value;
7226 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7229 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7231 args = dmb.Arguments;
7232 if (arguments != null)
7233 args.AddRange (arguments);
7234 } else if (mg == null) {
7235 if (arguments == null)
7236 args = new Arguments (1);
7240 args.Insert (0, new Argument (memberExpr));
7244 ec.Report.Error (1971, loc,
7245 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7250 if (arguments == null)
7251 args = new Arguments (1);
7255 MemberAccess ma = expr as MemberAccess;
7257 var inst = mg.InstanceExpression;
7258 var left_type = inst as TypeExpr;
7259 if (left_type != null) {
7260 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7261 } else if (inst != null) {
7263 // Any value type has to be pass as by-ref to get back the same
7264 // instance on which the member was called
7266 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7267 Argument.AType.Ref : Argument.AType.None;
7268 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7270 } else { // is SimpleName
7271 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7272 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7274 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7279 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7282 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7284 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7287 public override void FlowAnalysis (FlowAnalysisContext fc)
7289 if (mg.IsConditionallyExcluded)
7292 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7294 mg.FlowAnalysis (fc);
7296 if (arguments != null)
7297 arguments.FlowAnalysis (fc);
7299 if (conditional_access_receiver)
7300 fc.DefiniteAssignment = da;
7303 public override string GetSignatureForError ()
7305 return mg.GetSignatureForError ();
7308 public override bool HasConditionalAccess ()
7310 return expr.HasConditionalAccess ();
7314 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7315 // or the type dynamic, then the member is invocable
7317 public static bool IsMemberInvocable (MemberSpec member)
7319 switch (member.Kind) {
7320 case MemberKind.Event:
7322 case MemberKind.Field:
7323 case MemberKind.Property:
7324 var m = member as IInterfaceMemberSpec;
7325 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7331 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7333 if (!method.IsReservedMethod)
7336 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7339 ec.Report.SymbolRelatedToPreviousError (method);
7340 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7341 method.GetSignatureForError ());
7346 public override void Emit (EmitContext ec)
7348 if (mg.IsConditionallyExcluded)
7351 if (conditional_access_receiver)
7352 mg.EmitCall (ec, arguments, type, false);
7354 mg.EmitCall (ec, arguments, false);
7357 public override void EmitStatement (EmitContext ec)
7359 if (mg.IsConditionallyExcluded)
7362 if (conditional_access_receiver)
7363 mg.EmitCall (ec, arguments, type, true);
7365 mg.EmitCall (ec, arguments, true);
7368 public override SLE.Expression MakeExpression (BuilderContext ctx)
7370 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7373 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7376 throw new NotSupportedException ();
7378 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7379 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7383 public override object Accept (StructuralVisitor visitor)
7385 return visitor.Visit (this);
7390 // Implements simple new expression
7392 public class New : ExpressionStatement, IMemoryLocation
7394 protected Arguments arguments;
7397 // During bootstrap, it contains the RequestedType,
7398 // but if `type' is not null, it *might* contain a NewDelegate
7399 // (because of field multi-initialization)
7401 protected Expression RequestedType;
7403 protected MethodSpec method;
7405 public New (Expression requested_type, Arguments arguments, Location l)
7407 RequestedType = requested_type;
7408 this.arguments = arguments;
7413 public Arguments Arguments {
7420 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7422 public bool IsGeneratedStructConstructor {
7424 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7428 public Expression TypeExpression {
7430 return RequestedType;
7437 /// Converts complex core type syntax like 'new int ()' to simple constant
7439 public static Constant Constantify (TypeSpec t, Location loc)
7441 switch (t.BuiltinType) {
7442 case BuiltinTypeSpec.Type.Int:
7443 return new IntConstant (t, 0, loc);
7444 case BuiltinTypeSpec.Type.UInt:
7445 return new UIntConstant (t, 0, loc);
7446 case BuiltinTypeSpec.Type.Long:
7447 return new LongConstant (t, 0, loc);
7448 case BuiltinTypeSpec.Type.ULong:
7449 return new ULongConstant (t, 0, loc);
7450 case BuiltinTypeSpec.Type.Float:
7451 return new FloatConstant (t, 0, loc);
7452 case BuiltinTypeSpec.Type.Double:
7453 return new DoubleConstant (t, 0, loc);
7454 case BuiltinTypeSpec.Type.Short:
7455 return new ShortConstant (t, 0, loc);
7456 case BuiltinTypeSpec.Type.UShort:
7457 return new UShortConstant (t, 0, loc);
7458 case BuiltinTypeSpec.Type.SByte:
7459 return new SByteConstant (t, 0, loc);
7460 case BuiltinTypeSpec.Type.Byte:
7461 return new ByteConstant (t, 0, loc);
7462 case BuiltinTypeSpec.Type.Char:
7463 return new CharConstant (t, '\0', loc);
7464 case BuiltinTypeSpec.Type.Bool:
7465 return new BoolConstant (t, false, loc);
7466 case BuiltinTypeSpec.Type.Decimal:
7467 return new DecimalConstant (t, 0, loc);
7471 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7473 if (t.IsNullableType)
7474 return Nullable.LiftedNull.Create (t, loc);
7479 public override bool ContainsEmitWithAwait ()
7481 return arguments != null && arguments.ContainsEmitWithAwait ();
7485 // Checks whether the type is an interface that has the
7486 // [ComImport, CoClass] attributes and must be treated
7489 public Expression CheckComImport (ResolveContext ec)
7491 if (!type.IsInterface)
7495 // Turn the call into:
7496 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7498 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7499 if (real_class == null)
7502 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7503 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7504 return cast.Resolve (ec);
7507 public override Expression CreateExpressionTree (ResolveContext ec)
7510 if (method == null) {
7511 args = new Arguments (1);
7512 args.Add (new Argument (new TypeOf (type, loc)));
7514 args = Arguments.CreateForExpressionTree (ec,
7515 arguments, new TypeOfMethod (method, loc));
7518 return CreateExpressionFactoryCall (ec, "New", args);
7521 protected override Expression DoResolve (ResolveContext ec)
7523 if (RequestedType is TupleTypeExpr) {
7524 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
7527 type = RequestedType.ResolveAsType (ec);
7531 eclass = ExprClass.Value;
7533 if (type.IsPointer) {
7534 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7535 type.GetSignatureForError ());
7539 if (arguments == null) {
7540 Constant c = Constantify (type, RequestedType.Location);
7542 return ReducedExpression.Create (c, this);
7545 if (type.IsDelegate) {
7546 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7549 var tparam = type as TypeParameterSpec;
7550 if (tparam != null) {
7552 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7553 // where type parameter constraint is inflated to struct
7555 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7556 ec.Report.Error (304, loc,
7557 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7558 type.GetSignatureForError ());
7561 if ((arguments != null) && (arguments.Count != 0)) {
7562 ec.Report.Error (417, loc,
7563 "`{0}': cannot provide arguments when creating an instance of a variable type",
7564 type.GetSignatureForError ());
7570 if (type.IsStatic) {
7571 ec.Report.SymbolRelatedToPreviousError (type);
7572 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7576 if (type.IsInterface || type.IsAbstract){
7577 if (!TypeManager.IsGenericType (type)) {
7578 RequestedType = CheckComImport (ec);
7579 if (RequestedType != null)
7580 return RequestedType;
7583 ec.Report.SymbolRelatedToPreviousError (type);
7584 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7589 if (arguments != null) {
7590 arguments.Resolve (ec, out dynamic);
7595 method = ConstructorLookup (ec, type, ref arguments, loc);
7598 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7599 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7605 void DoEmitTypeParameter (EmitContext ec)
7607 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7611 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7612 ec.Emit (OpCodes.Call, ctor_factory);
7616 // This Emit can be invoked in two contexts:
7617 // * As a mechanism that will leave a value on the stack (new object)
7618 // * As one that wont (init struct)
7620 // If we are dealing with a ValueType, we have a few
7621 // situations to deal with:
7623 // * The target is a ValueType, and we have been provided
7624 // the instance (this is easy, we are being assigned).
7626 // * The target of New is being passed as an argument,
7627 // to a boxing operation or a function that takes a
7630 // In this case, we need to create a temporary variable
7631 // that is the argument of New.
7633 // Returns whether a value is left on the stack
7635 // *** Implementation note ***
7637 // To benefit from this optimization, each assignable expression
7638 // has to manually cast to New and call this Emit.
7640 // TODO: It's worth to implement it for arrays and fields
7642 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7644 bool is_value_type = type.IsStructOrEnum;
7645 VariableReference vr = target as VariableReference;
7647 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7649 if (target != null && is_value_type && (vr != null || method == null)) {
7650 if (prepare_await) {
7651 arguments = arguments.Emit (ec, false, true);
7652 prepare_await = false;
7655 target.AddressOf (ec, AddressOp.Store);
7656 } else if (vr != null && vr.IsRef) {
7660 if (arguments != null) {
7662 arguments = arguments.Emit (ec, false, true);
7664 arguments.Emit (ec);
7667 if (is_value_type) {
7668 if (method == null) {
7669 ec.Emit (OpCodes.Initobj, type);
7674 ec.MarkCallEntry (loc);
7675 ec.Emit (OpCodes.Call, method);
7680 if (type is TypeParameterSpec) {
7681 DoEmitTypeParameter (ec);
7685 ec.MarkCallEntry (loc);
7686 ec.Emit (OpCodes.Newobj, method);
7690 public override void Emit (EmitContext ec)
7692 LocalTemporary v = null;
7693 if (method == null && type.IsStructOrEnum) {
7694 // TODO: Use temporary variable from pool
7695 v = new LocalTemporary (type);
7702 public override void EmitStatement (EmitContext ec)
7704 LocalTemporary v = null;
7705 if (method == null && TypeSpec.IsValueType (type)) {
7706 // TODO: Use temporary variable from pool
7707 v = new LocalTemporary (type);
7711 ec.Emit (OpCodes.Pop);
7714 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7719 public override void FlowAnalysis (FlowAnalysisContext fc)
7721 if (arguments != null)
7722 arguments.FlowAnalysis (fc);
7725 public void AddressOf (EmitContext ec, AddressOp mode)
7727 EmitAddressOf (ec, mode);
7730 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7732 LocalTemporary value_target = new LocalTemporary (type);
7734 if (type is TypeParameterSpec) {
7735 DoEmitTypeParameter (ec);
7736 value_target.Store (ec);
7737 value_target.AddressOf (ec, mode);
7738 return value_target;
7741 value_target.AddressOf (ec, AddressOp.Store);
7743 if (method == null) {
7744 ec.Emit (OpCodes.Initobj, type);
7746 if (arguments != null)
7747 arguments.Emit (ec);
7749 ec.Emit (OpCodes.Call, method);
7752 value_target.AddressOf (ec, mode);
7753 return value_target;
7756 protected override void CloneTo (CloneContext clonectx, Expression t)
7758 New target = (New) t;
7760 target.RequestedType = RequestedType.Clone (clonectx);
7761 if (arguments != null){
7762 target.arguments = arguments.Clone (clonectx);
7766 public override SLE.Expression MakeExpression (BuilderContext ctx)
7769 return base.MakeExpression (ctx);
7771 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7775 public override object Accept (StructuralVisitor visitor)
7777 return visitor.Visit (this);
7782 // Array initializer expression, the expression is allowed in
7783 // variable or field initialization only which makes it tricky as
7784 // the type has to be infered based on the context either from field
7785 // type or variable type (think of multiple declarators)
7787 public class ArrayInitializer : Expression
7789 List<Expression> elements;
7790 BlockVariable variable;
7792 public ArrayInitializer (List<Expression> init, Location loc)
7798 public ArrayInitializer (int count, Location loc)
7799 : this (new List<Expression> (count), loc)
7803 public ArrayInitializer (Location loc)
7811 get { return elements.Count; }
7814 public List<Expression> Elements {
7820 public Expression this [int index] {
7822 return elements [index];
7826 public BlockVariable VariableDeclaration {
7837 public void Add (Expression expr)
7839 elements.Add (expr);
7842 public override bool ContainsEmitWithAwait ()
7844 throw new NotSupportedException ();
7847 public override Expression CreateExpressionTree (ResolveContext ec)
7849 throw new NotSupportedException ("ET");
7852 protected override void CloneTo (CloneContext clonectx, Expression t)
7854 var target = (ArrayInitializer) t;
7856 target.elements = new List<Expression> (elements.Count);
7857 foreach (var element in elements)
7858 target.elements.Add (element.Clone (clonectx));
7861 protected override Expression DoResolve (ResolveContext rc)
7863 var current_field = rc.CurrentMemberDefinition as FieldBase;
7864 TypeExpression type;
7865 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7866 type = new TypeExpression (current_field.MemberType, current_field.Location);
7867 } else if (variable != null) {
7868 if (variable.TypeExpression is VarExpr) {
7869 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7870 return EmptyExpression.Null;
7873 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7875 throw new NotImplementedException ("Unexpected array initializer context");
7878 return new ArrayCreation (type, this).Resolve (rc);
7881 public override void Emit (EmitContext ec)
7883 throw new InternalErrorException ("Missing Resolve call");
7886 public override void FlowAnalysis (FlowAnalysisContext fc)
7888 throw new InternalErrorException ("Missing Resolve call");
7891 public override object Accept (StructuralVisitor visitor)
7893 return visitor.Visit (this);
7898 /// 14.5.10.2: Represents an array creation expression.
7902 /// There are two possible scenarios here: one is an array creation
7903 /// expression that specifies the dimensions and optionally the
7904 /// initialization data and the other which does not need dimensions
7905 /// specified but where initialization data is mandatory.
7907 public class ArrayCreation : Expression
7909 FullNamedExpression requested_base_type;
7910 ArrayInitializer initializers;
7913 // The list of Argument types.
7914 // This is used to construct the `newarray' or constructor signature
7916 protected List<Expression> arguments;
7918 protected TypeSpec array_element_type;
7920 protected int dimensions;
7921 protected readonly ComposedTypeSpecifier rank;
7922 Expression first_emit;
7923 LocalTemporary first_emit_temp;
7925 protected List<Expression> array_data;
7927 Dictionary<int, int> bounds;
7930 // The number of constants in array initializers
7931 int const_initializers_count;
7932 bool only_constant_initializers;
7934 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7935 : this (requested_base_type, rank, initializers, l)
7937 arguments = new List<Expression> (exprs);
7938 num_arguments = arguments.Count;
7942 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7944 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7946 this.requested_base_type = requested_base_type;
7948 this.initializers = initializers;
7952 num_arguments = rank.Dimension;
7956 // For compiler generated single dimensional arrays only
7958 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7959 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7964 // For expressions like int[] foo = { 1, 2, 3 };
7966 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7967 : this (requested_base_type, null, initializers, initializers.Location)
7971 public bool NoEmptyInterpolation { get; set; }
7973 public ComposedTypeSpecifier Rank {
7979 public FullNamedExpression TypeExpression {
7981 return this.requested_base_type;
7985 public ArrayInitializer Initializers {
7987 return this.initializers;
7991 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7993 if (initializers != null && bounds == null) {
7995 // We use this to store all the data values in the order in which we
7996 // will need to store them in the byte blob later
7998 array_data = new List<Expression> (probe.Count);
7999 bounds = new Dictionary<int, int> ();
8002 if (specified_dims) {
8003 Expression a = arguments [idx];
8008 a = ConvertExpressionToArrayIndex (ec, a);
8014 if (initializers != null) {
8015 Constant c = a as Constant;
8016 if (c == null && a is ArrayIndexCast)
8017 c = ((ArrayIndexCast) a).Child as Constant;
8020 ec.Report.Error (150, a.Location, "A constant value is expected");
8026 value = System.Convert.ToInt32 (c.GetValue ());
8028 ec.Report.Error (150, a.Location, "A constant value is expected");
8032 // TODO: probe.Count does not fit ulong in
8033 if (value != probe.Count) {
8034 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8038 bounds[idx] = value;
8042 if (initializers == null)
8045 for (int i = 0; i < probe.Count; ++i) {
8047 if (o is ArrayInitializer) {
8048 var sub_probe = o as ArrayInitializer;
8049 if (idx + 1 >= dimensions){
8050 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8054 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8055 if (!bounds.ContainsKey(idx + 1))
8056 bounds[idx + 1] = sub_probe.Count;
8058 if (bounds[idx + 1] != sub_probe.Count) {
8059 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8063 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8066 } else if (child_bounds > 1) {
8067 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8069 Expression element = ResolveArrayElement (ec, o);
8070 if (element == null)
8073 // Initializers with the default values can be ignored
8074 Constant c = element as Constant;
8076 if (!c.IsDefaultInitializer (array_element_type)) {
8077 ++const_initializers_count;
8080 only_constant_initializers = false;
8083 array_data.Add (element);
8090 public override bool ContainsEmitWithAwait ()
8092 foreach (var arg in arguments) {
8093 if (arg.ContainsEmitWithAwait ())
8097 return InitializersContainAwait ();
8100 public override Expression CreateExpressionTree (ResolveContext ec)
8104 if (array_data == null) {
8105 args = new Arguments (arguments.Count + 1);
8106 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8107 foreach (Expression a in arguments)
8108 args.Add (new Argument (a.CreateExpressionTree (ec)));
8110 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8113 if (dimensions > 1) {
8114 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8118 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8119 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8120 if (array_data != null) {
8121 for (int i = 0; i < array_data.Count; ++i) {
8122 Expression e = array_data [i];
8123 args.Add (new Argument (e.CreateExpressionTree (ec)));
8127 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8130 void UpdateIndices (ResolveContext rc)
8133 for (var probe = initializers; probe != null;) {
8134 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8136 bounds[i++] = probe.Count;
8138 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8139 probe = (ArrayInitializer) probe[0];
8140 } else if (dimensions > i) {
8148 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8150 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8153 public override void FlowAnalysis (FlowAnalysisContext fc)
8155 foreach (var arg in arguments)
8156 arg.FlowAnalysis (fc);
8158 if (array_data != null) {
8159 foreach (var ad in array_data)
8160 ad.FlowAnalysis (fc);
8164 bool InitializersContainAwait ()
8166 if (array_data == null)
8169 foreach (var expr in array_data) {
8170 if (expr.ContainsEmitWithAwait ())
8177 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8179 element = element.Resolve (ec);
8180 if (element == null)
8183 var te = element as CompoundAssign.TargetExpression;
8185 for (int i = 1; i < initializers.Count; ++i) {
8186 if (initializers [i].ContainsEmitWithAwait ()) {
8187 te.RequiresEmitWithAwait = true;
8192 if (!te.RequiresEmitWithAwait) {
8193 if (first_emit != null)
8194 throw new InternalErrorException ("Can only handle one mutator at a time");
8195 first_emit = element;
8196 element = first_emit_temp = new LocalTemporary (element.Type);
8200 return Convert.ImplicitConversionRequired (
8201 ec, element, array_element_type, loc);
8204 protected bool ResolveInitializers (ResolveContext ec)
8207 only_constant_initializers = true;
8210 if (arguments != null) {
8212 for (int i = 0; i < arguments.Count; ++i) {
8213 res &= CheckIndices (ec, initializers, i, true, dimensions);
8214 if (initializers != null)
8221 arguments = new List<Expression> ();
8223 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8232 // Resolved the type of the array
8234 bool ResolveArrayType (ResolveContext ec)
8239 FullNamedExpression array_type_expr;
8240 if (num_arguments > 0) {
8241 array_type_expr = new ComposedCast (requested_base_type, rank);
8243 array_type_expr = requested_base_type;
8246 type = array_type_expr.ResolveAsType (ec);
8247 if (array_type_expr == null)
8250 var ac = type as ArrayContainer;
8252 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8256 array_element_type = ac.Element;
8257 dimensions = ac.Rank;
8262 protected override Expression DoResolve (ResolveContext ec)
8267 if (!ResolveArrayType (ec))
8271 // validate the initializers and fill in any missing bits
8273 if (!ResolveInitializers (ec))
8276 eclass = ExprClass.Value;
8280 byte [] MakeByteBlob ()
8285 int count = array_data.Count;
8287 TypeSpec element_type = array_element_type;
8288 if (element_type.IsEnum)
8289 element_type = EnumSpec.GetUnderlyingType (element_type);
8291 factor = BuiltinTypeSpec.GetSize (element_type);
8293 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8295 data = new byte [(count * factor + 3) & ~3];
8298 for (int i = 0; i < count; ++i) {
8299 var c = array_data[i] as Constant;
8305 object v = c.GetValue ();
8307 switch (element_type.BuiltinType) {
8308 case BuiltinTypeSpec.Type.Long:
8309 long lval = (long) v;
8311 for (int j = 0; j < factor; ++j) {
8312 data[idx + j] = (byte) (lval & 0xFF);
8316 case BuiltinTypeSpec.Type.ULong:
8317 ulong ulval = (ulong) v;
8319 for (int j = 0; j < factor; ++j) {
8320 data[idx + j] = (byte) (ulval & 0xFF);
8321 ulval = (ulval >> 8);
8324 case BuiltinTypeSpec.Type.Float:
8325 var fval = SingleConverter.SingleToInt32Bits((float) v);
8327 data[idx] = (byte) (fval & 0xff);
8328 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8329 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8330 data[idx + 3] = (byte) (fval >> 24);
8332 case BuiltinTypeSpec.Type.Double:
8333 element = BitConverter.GetBytes ((double) v);
8335 for (int j = 0; j < factor; ++j)
8336 data[idx + j] = element[j];
8338 // FIXME: Handle the ARM float format.
8339 if (!BitConverter.IsLittleEndian)
8340 System.Array.Reverse (data, idx, 8);
8342 case BuiltinTypeSpec.Type.Char:
8343 int chval = (int) ((char) v);
8345 data[idx] = (byte) (chval & 0xff);
8346 data[idx + 1] = (byte) (chval >> 8);
8348 case BuiltinTypeSpec.Type.Short:
8349 int sval = (int) ((short) v);
8351 data[idx] = (byte) (sval & 0xff);
8352 data[idx + 1] = (byte) (sval >> 8);
8354 case BuiltinTypeSpec.Type.UShort:
8355 int usval = (int) ((ushort) v);
8357 data[idx] = (byte) (usval & 0xff);
8358 data[idx + 1] = (byte) (usval >> 8);
8360 case BuiltinTypeSpec.Type.Int:
8363 data[idx] = (byte) (val & 0xff);
8364 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8365 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8366 data[idx + 3] = (byte) (val >> 24);
8368 case BuiltinTypeSpec.Type.UInt:
8369 uint uval = (uint) v;
8371 data[idx] = (byte) (uval & 0xff);
8372 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8373 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8374 data[idx + 3] = (byte) (uval >> 24);
8376 case BuiltinTypeSpec.Type.SByte:
8377 data[idx] = (byte) (sbyte) v;
8379 case BuiltinTypeSpec.Type.Byte:
8380 data[idx] = (byte) v;
8382 case BuiltinTypeSpec.Type.Bool:
8383 data[idx] = (byte) ((bool) v ? 1 : 0);
8385 case BuiltinTypeSpec.Type.Decimal:
8386 int[] bits = Decimal.GetBits ((decimal) v);
8389 // FIXME: For some reason, this doesn't work on the MS runtime.
8390 int[] nbits = new int[4];
8396 for (int j = 0; j < 4; j++) {
8397 data[p++] = (byte) (nbits[j] & 0xff);
8398 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8399 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8400 data[p++] = (byte) (nbits[j] >> 24);
8404 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8413 public override SLE.Expression MakeExpression (BuilderContext ctx)
8416 return base.MakeExpression (ctx);
8418 var initializers = new SLE.Expression [array_data.Count];
8419 for (var i = 0; i < initializers.Length; i++) {
8420 if (array_data [i] == null)
8421 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8423 initializers [i] = array_data [i].MakeExpression (ctx);
8426 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8431 // Emits the initializers for the array
8433 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8435 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8440 // First, the static data
8442 byte [] data = MakeByteBlob ();
8443 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8445 if (stackArray == null) {
8446 ec.Emit (OpCodes.Dup);
8448 stackArray.Emit (ec);
8451 ec.Emit (OpCodes.Ldtoken, fb);
8452 ec.Emit (OpCodes.Call, m);
8457 // Emits pieces of the array that can not be computed at compile
8458 // time (variables and string locations).
8460 // This always expect the top value on the stack to be the array
8462 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8464 int dims = bounds.Count;
8465 var current_pos = new int [dims];
8467 for (int i = 0; i < array_data.Count; i++){
8469 Expression e = array_data [i];
8470 var c = e as Constant;
8472 // Constant can be initialized via StaticInitializer
8473 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8477 if (stackArray != null) {
8478 if (e.ContainsEmitWithAwait ()) {
8479 e = e.EmitToField (ec);
8482 stackArray.EmitLoad (ec);
8484 ec.Emit (OpCodes.Dup);
8487 for (int idx = 0; idx < dims; idx++)
8488 ec.EmitInt (current_pos [idx]);
8491 // If we are dealing with a struct, get the
8492 // address of it, so we can store it.
8494 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8495 ec.Emit (OpCodes.Ldelema, etype);
8499 ec.EmitArrayStore ((ArrayContainer) type);
8505 for (int j = dims - 1; j >= 0; j--){
8507 if (current_pos [j] < bounds [j])
8509 current_pos [j] = 0;
8513 if (stackArray != null)
8514 stackArray.PrepareCleanup (ec);
8517 public override void Emit (EmitContext ec)
8519 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8522 var await_field = EmitToFieldSource (ec);
8523 if (await_field != null)
8524 await_field.Emit (ec);
8527 bool EmitOptimizedEmpty (EmitContext ec)
8529 if (arguments.Count != 1 || dimensions != 1)
8532 var c = arguments [0] as Constant;
8533 if (c == null || !c.IsZeroInteger)
8536 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8537 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8540 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8541 ec.Emit (OpCodes.Call, m);
8545 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8547 if (first_emit != null) {
8548 first_emit.Emit (ec);
8549 first_emit_temp.Store (ec);
8552 StackFieldExpr await_stack_field;
8553 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8554 await_stack_field = ec.GetTemporaryField (type);
8557 await_stack_field = null;
8560 EmitExpressionsList (ec, arguments);
8562 ec.EmitArrayNew ((ArrayContainer) type);
8564 if (initializers == null)
8565 return await_stack_field;
8567 if (await_stack_field != null)
8568 await_stack_field.EmitAssignFromStack (ec);
8572 // Emit static initializer for arrays which contain more than 2 items and
8573 // the static initializer will initialize at least 25% of array values or there
8574 // is more than 10 items to be initialized
8576 // NOTE: const_initializers_count does not contain default constant values.
8578 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8579 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8580 EmitStaticInitializers (ec, await_stack_field);
8582 if (!only_constant_initializers)
8583 EmitDynamicInitializers (ec, false, await_stack_field);
8587 EmitDynamicInitializers (ec, true, await_stack_field);
8590 if (first_emit_temp != null)
8591 first_emit_temp.Release (ec);
8593 return await_stack_field;
8596 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8598 // no multi dimensional or jagged arrays
8599 if (arguments.Count != 1 || array_element_type.IsArray) {
8600 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8604 // No array covariance, except for array -> object
8605 if (type != targetType) {
8606 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8607 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8611 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8612 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8617 // Single dimensional array of 0 size
8618 if (array_data == null) {
8619 IntConstant ic = arguments[0] as IntConstant;
8620 if (ic == null || !ic.IsDefaultValue) {
8621 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8629 enc.Encode (array_data.Count);
8630 foreach (var element in array_data) {
8631 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8635 protected override void CloneTo (CloneContext clonectx, Expression t)
8637 ArrayCreation target = (ArrayCreation) t;
8639 if (requested_base_type != null)
8640 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8642 if (arguments != null){
8643 target.arguments = new List<Expression> (arguments.Count);
8644 foreach (Expression e in arguments)
8645 target.arguments.Add (e.Clone (clonectx));
8648 if (initializers != null)
8649 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8652 public override object Accept (StructuralVisitor visitor)
8654 return visitor.Visit (this);
8659 // Represents an implicitly typed array epxression
8661 class ImplicitlyTypedArrayCreation : ArrayCreation
8663 TypeInferenceContext best_type_inference;
8665 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8666 : base (null, rank, initializers, loc)
8670 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8671 : base (null, initializers, loc)
8675 protected override Expression DoResolve (ResolveContext ec)
8680 dimensions = rank.Dimension;
8682 best_type_inference = new TypeInferenceContext ();
8684 if (!ResolveInitializers (ec))
8687 best_type_inference.FixAllTypes (ec);
8688 array_element_type = best_type_inference.InferredTypeArguments[0];
8689 best_type_inference = null;
8691 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
8692 ec.Report.Error (826, loc,
8693 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8698 // At this point we found common base type for all initializer elements
8699 // but we have to be sure that all static initializer elements are of
8702 UnifyInitializerElement (ec);
8704 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8705 eclass = ExprClass.Value;
8710 // Converts static initializer only
8712 void UnifyInitializerElement (ResolveContext ec)
8714 for (int i = 0; i < array_data.Count; ++i) {
8715 Expression e = array_data[i];
8717 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8721 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8723 element = element.Resolve (ec);
8724 if (element != null)
8725 best_type_inference.AddCommonTypeBound (element.Type);
8731 sealed class CompilerGeneratedThis : This
8733 public CompilerGeneratedThis (TypeSpec type, Location loc)
8739 protected override Expression DoResolve (ResolveContext rc)
8741 eclass = ExprClass.Variable;
8743 var block = rc.CurrentBlock;
8744 if (block != null) {
8745 var top = block.ParametersBlock.TopBlock;
8746 if (top.ThisVariable != null)
8747 variable_info = top.ThisVariable.VariableInfo;
8754 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8756 return DoResolve (rc);
8759 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8766 /// Represents the `this' construct
8769 public class This : VariableReference
8771 sealed class ThisVariable : ILocalVariable
8773 public static readonly ILocalVariable Instance = new ThisVariable ();
8775 public void Emit (EmitContext ec)
8780 public void EmitAssign (EmitContext ec)
8782 throw new InvalidOperationException ();
8785 public void EmitAddressOf (EmitContext ec)
8791 protected VariableInfo variable_info;
8793 public This (Location loc)
8800 public override string Name {
8801 get { return "this"; }
8804 public override bool IsLockedByStatement {
8812 public override bool IsRef {
8813 get { return type.IsStruct; }
8816 public override bool IsSideEffectFree {
8822 protected override ILocalVariable Variable {
8823 get { return ThisVariable.Instance; }
8826 public override VariableInfo VariableInfo {
8827 get { return variable_info; }
8830 public override bool IsFixed {
8831 get { return false; }
8836 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8839 // It's null for all cases when we don't need to check `this'
8840 // definitive assignment
8842 if (variable_info == null)
8845 if (fc.IsDefinitelyAssigned (variable_info))
8848 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8851 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8853 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8854 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8855 } else if (ec.CurrentAnonymousMethod != null) {
8856 ec.Report.Error (1673, loc,
8857 "Anonymous methods inside structs cannot access instance members of `this'. " +
8858 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8860 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8864 public override void FlowAnalysis (FlowAnalysisContext fc)
8866 CheckStructThisDefiniteAssignment (fc);
8869 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8874 AnonymousMethodStorey storey = ae.Storey;
8875 return storey != null ? storey.HoistedThis : null;
8878 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8880 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8883 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8886 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8892 public virtual void ResolveBase (ResolveContext ec)
8894 eclass = ExprClass.Variable;
8895 type = ec.CurrentType;
8897 if (!IsThisAvailable (ec, false)) {
8898 Error_ThisNotAvailable (ec);
8902 var block = ec.CurrentBlock;
8903 if (block != null) {
8904 var top = block.ParametersBlock.TopBlock;
8905 if (top.ThisVariable != null)
8906 variable_info = top.ThisVariable.VariableInfo;
8908 AnonymousExpression am = ec.CurrentAnonymousMethod;
8909 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8911 // Hoisted this is almost like hoisted variable but not exactly. When
8912 // there is no variable hoisted we can simply emit an instance method
8913 // without lifting this into a storey. Unfotunatelly this complicates
8914 // things in other cases because we don't know where this will be hoisted
8915 // until top-level block is fully resolved
8917 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8918 am.SetHasThisAccess ();
8923 protected override Expression DoResolve (ResolveContext ec)
8929 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8931 if (eclass == ExprClass.Unresolved)
8935 if (right_side == EmptyExpression.UnaryAddress)
8936 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8937 else if (right_side == EmptyExpression.OutAccess)
8938 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8940 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8946 public override int GetHashCode()
8948 throw new NotImplementedException ();
8951 public override bool Equals (object obj)
8953 This t = obj as This;
8960 protected override void CloneTo (CloneContext clonectx, Expression t)
8965 public override void SetHasAddressTaken ()
8970 public override object Accept (StructuralVisitor visitor)
8972 return visitor.Visit (this);
8977 /// Represents the `__arglist' construct
8979 public class ArglistAccess : Expression
8981 public ArglistAccess (Location loc)
8986 protected override void CloneTo (CloneContext clonectx, Expression target)
8991 public override bool ContainsEmitWithAwait ()
8996 public override Expression CreateExpressionTree (ResolveContext ec)
8998 throw new NotSupportedException ("ET");
9001 protected override Expression DoResolve (ResolveContext ec)
9003 eclass = ExprClass.Variable;
9004 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
9006 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
9007 ec.Report.Error (190, loc,
9008 "The __arglist construct is valid only within a variable argument method");
9014 public override void Emit (EmitContext ec)
9016 ec.Emit (OpCodes.Arglist);
9019 public override object Accept (StructuralVisitor visitor)
9021 return visitor.Visit (this);
9026 /// Represents the `__arglist (....)' construct
9028 public class Arglist : Expression
9030 Arguments arguments;
9032 public Arglist (Location loc)
9037 public Arglist (Arguments args, Location l)
9043 public Arguments Arguments {
9049 public MetaType[] ArgumentTypes {
9051 if (arguments == null)
9052 return MetaType.EmptyTypes;
9054 var retval = new MetaType[arguments.Count];
9055 for (int i = 0; i < retval.Length; i++)
9056 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9062 public override bool ContainsEmitWithAwait ()
9064 throw new NotImplementedException ();
9067 public override Expression CreateExpressionTree (ResolveContext ec)
9069 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9073 protected override Expression DoResolve (ResolveContext ec)
9075 eclass = ExprClass.Variable;
9076 type = InternalType.Arglist;
9077 if (arguments != null) {
9078 bool dynamic; // Can be ignored as there is always only 1 overload
9079 arguments.Resolve (ec, out dynamic);
9085 public override void Emit (EmitContext ec)
9087 if (arguments != null)
9088 arguments.Emit (ec);
9091 protected override void CloneTo (CloneContext clonectx, Expression t)
9093 Arglist target = (Arglist) t;
9095 if (arguments != null)
9096 target.arguments = arguments.Clone (clonectx);
9099 public override object Accept (StructuralVisitor visitor)
9101 return visitor.Visit (this);
9105 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9107 FullNamedExpression texpr;
9109 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9116 public FullNamedExpression TypeExpression {
9122 public override bool ContainsEmitWithAwait ()
9127 public void AddressOf (EmitContext ec, AddressOp mode)
9130 ec.Emit (OpCodes.Refanyval, type);
9133 protected override Expression DoResolve (ResolveContext rc)
9135 expr = expr.Resolve (rc);
9136 type = texpr.ResolveAsType (rc);
9137 if (expr == null || type == null)
9140 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9141 eclass = ExprClass.Variable;
9145 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9147 return DoResolve (rc);
9150 public override void Emit (EmitContext ec)
9153 ec.Emit (OpCodes.Refanyval, type);
9154 ec.EmitLoadFromPtr (type);
9157 public void Emit (EmitContext ec, bool leave_copy)
9159 throw new NotImplementedException ();
9162 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9165 ec.Emit (OpCodes.Refanyval, type);
9168 LocalTemporary temporary = null;
9170 ec.Emit (OpCodes.Dup);
9171 temporary = new LocalTemporary (source.Type);
9172 temporary.Store (ec);
9175 ec.EmitStoreFromPtr (type);
9177 if (temporary != null) {
9178 temporary.Emit (ec);
9179 temporary.Release (ec);
9183 public override object Accept (StructuralVisitor visitor)
9185 return visitor.Visit (this);
9189 public class RefTypeExpr : ShimExpression
9191 public RefTypeExpr (Expression expr, Location loc)
9197 protected override Expression DoResolve (ResolveContext rc)
9199 expr = expr.Resolve (rc);
9203 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9207 type = rc.BuiltinTypes.Type;
9208 eclass = ExprClass.Value;
9212 public override void Emit (EmitContext ec)
9215 ec.Emit (OpCodes.Refanytype);
9216 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9218 ec.Emit (OpCodes.Call, m);
9221 public override object Accept (StructuralVisitor visitor)
9223 return visitor.Visit (this);
9227 public class MakeRefExpr : ShimExpression
9229 public MakeRefExpr (Expression expr, Location loc)
9235 public override bool ContainsEmitWithAwait ()
9237 throw new NotImplementedException ();
9240 protected override Expression DoResolve (ResolveContext rc)
9242 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9243 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9244 eclass = ExprClass.Value;
9248 public override void Emit (EmitContext ec)
9250 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9251 ec.Emit (OpCodes.Mkrefany, expr.Type);
9254 public override object Accept (StructuralVisitor visitor)
9256 return visitor.Visit (this);
9261 /// Implements the typeof operator
9263 public class TypeOf : Expression {
9264 FullNamedExpression QueriedType;
9267 public TypeOf (FullNamedExpression queried_type, Location l)
9269 QueriedType = queried_type;
9274 // Use this constructor for any compiler generated typeof expression
9276 public TypeOf (TypeSpec type, Location loc)
9278 this.typearg = type;
9284 public override bool IsSideEffectFree {
9290 public TypeSpec TypeArgument {
9296 public FullNamedExpression TypeExpression {
9305 protected override void CloneTo (CloneContext clonectx, Expression t)
9307 TypeOf target = (TypeOf) t;
9308 if (QueriedType != null)
9309 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9312 public override bool ContainsEmitWithAwait ()
9317 public override Expression CreateExpressionTree (ResolveContext ec)
9319 Arguments args = new Arguments (2);
9320 args.Add (new Argument (this));
9321 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9322 return CreateExpressionFactoryCall (ec, "Constant", args);
9325 protected override Expression DoResolve (ResolveContext ec)
9327 if (eclass != ExprClass.Unresolved)
9330 if (typearg == null) {
9332 // Pointer types are allowed without explicit unsafe, they are just tokens
9334 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9335 typearg = QueriedType.ResolveAsType (ec, true);
9338 if (typearg == null)
9341 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9342 ec.Report.Error (1962, QueriedType.Location,
9343 "The typeof operator cannot be used on the dynamic type");
9347 type = ec.BuiltinTypes.Type;
9349 // Even though what is returned is a type object, it's treated as a value by the compiler.
9350 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9351 eclass = ExprClass.Value;
9355 static bool ContainsDynamicType (TypeSpec type)
9357 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9360 var element_container = type as ElementTypeSpec;
9361 if (element_container != null)
9362 return ContainsDynamicType (element_container.Element);
9364 foreach (var t in type.TypeArguments) {
9365 if (ContainsDynamicType (t)) {
9373 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9375 // Target type is not System.Type therefore must be object
9376 // and we need to use different encoding sequence
9377 if (targetType != type)
9380 if (typearg is InflatedTypeSpec) {
9383 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9384 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9385 typearg.GetSignatureForError ());
9389 gt = gt.DeclaringType;
9390 } while (gt != null);
9393 if (ContainsDynamicType (typearg)) {
9394 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9398 enc.EncodeTypeName (typearg);
9401 public override void Emit (EmitContext ec)
9403 ec.Emit (OpCodes.Ldtoken, typearg);
9404 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9406 ec.Emit (OpCodes.Call, m);
9409 public override object Accept (StructuralVisitor visitor)
9411 return visitor.Visit (this);
9415 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9417 public TypeOfMethod (MethodSpec method, Location loc)
9418 : base (method, loc)
9422 protected override Expression DoResolve (ResolveContext ec)
9424 if (member.IsConstructor) {
9425 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9427 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9433 return base.DoResolve (ec);
9436 public override void Emit (EmitContext ec)
9438 ec.Emit (OpCodes.Ldtoken, member);
9441 ec.Emit (OpCodes.Castclass, type);
9444 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9446 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9449 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9451 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9455 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9457 protected readonly T member;
9459 protected TypeOfMember (T member, Location loc)
9461 this.member = member;
9465 public override bool IsSideEffectFree {
9471 public override bool ContainsEmitWithAwait ()
9476 public override Expression CreateExpressionTree (ResolveContext ec)
9478 Arguments args = new Arguments (2);
9479 args.Add (new Argument (this));
9480 args.Add (new Argument (new TypeOf (type, loc)));
9481 return CreateExpressionFactoryCall (ec, "Constant", args);
9484 protected override Expression DoResolve (ResolveContext ec)
9486 eclass = ExprClass.Value;
9490 public override void Emit (EmitContext ec)
9492 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9493 PredefinedMember<MethodSpec> p;
9495 p = GetTypeFromHandleGeneric (ec);
9496 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9498 p = GetTypeFromHandle (ec);
9501 var mi = p.Resolve (loc);
9503 ec.Emit (OpCodes.Call, mi);
9506 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9507 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9510 sealed class TypeOfField : TypeOfMember<FieldSpec>
9512 public TypeOfField (FieldSpec field, Location loc)
9517 protected override Expression DoResolve (ResolveContext ec)
9519 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9523 return base.DoResolve (ec);
9526 public override void Emit (EmitContext ec)
9528 ec.Emit (OpCodes.Ldtoken, member);
9532 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9534 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9537 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9539 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9544 /// Implements the sizeof expression
9546 public class SizeOf : Expression {
9547 readonly Expression texpr;
9548 TypeSpec type_queried;
9550 public SizeOf (Expression queried_type, Location l)
9552 this.texpr = queried_type;
9556 public override bool IsSideEffectFree {
9562 public Expression TypeExpression {
9568 public override bool ContainsEmitWithAwait ()
9573 public override Expression CreateExpressionTree (ResolveContext ec)
9575 Error_PointerInsideExpressionTree (ec);
9579 protected override Expression DoResolve (ResolveContext ec)
9581 type_queried = texpr.ResolveAsType (ec);
9582 if (type_queried == null)
9585 if (type_queried.IsEnum)
9586 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9588 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9590 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9593 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9598 ec.Report.Error (233, loc,
9599 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9600 type_queried.GetSignatureForError ());
9603 type = ec.BuiltinTypes.Int;
9604 eclass = ExprClass.Value;
9608 public override void Emit (EmitContext ec)
9610 ec.Emit (OpCodes.Sizeof, type_queried);
9613 protected override void CloneTo (CloneContext clonectx, Expression t)
9617 public override object Accept (StructuralVisitor visitor)
9619 return visitor.Visit (this);
9624 /// Implements the qualified-alias-member (::) expression.
9626 public class QualifiedAliasMember : MemberAccess
9628 readonly string alias;
9629 public static readonly string GlobalAlias = "global";
9631 public QualifiedAliasMember (string alias, string identifier, Location l)
9632 : base (null, identifier, l)
9637 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9638 : base (null, identifier, targs, l)
9643 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9644 : base (null, identifier, arity, l)
9649 public string Alias {
9655 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9657 if (alias == GlobalAlias)
9658 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9660 int errors = mc.Module.Compiler.Report.Errors;
9661 var expr = mc.LookupNamespaceAlias (alias);
9663 if (errors == mc.Module.Compiler.Report.Errors)
9664 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9672 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9674 expr = CreateExpressionFromAlias (mc);
9678 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9681 protected override Expression DoResolve (ResolveContext rc)
9683 return ResolveAsTypeOrNamespace (rc, false);
9686 public override string GetSignatureForError ()
9689 if (targs != null) {
9690 name = Name + "<" + targs.GetSignatureForError () + ">";
9693 return alias + "::" + name;
9696 public override bool HasConditionalAccess ()
9701 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9703 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9704 rc.Module.Compiler.Report.Error (687, loc,
9705 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9706 GetSignatureForError ());
9711 return DoResolve (rc);
9714 protected override void CloneTo (CloneContext clonectx, Expression t)
9719 public override object Accept (StructuralVisitor visitor)
9721 return visitor.Visit (this);
9726 /// Implements the member access expression
9728 public class MemberAccess : ATypeNameExpression
9730 protected Expression expr;
9732 public MemberAccess (Expression expr, string id)
9733 : base (id, expr.Location)
9738 public MemberAccess (Expression expr, string identifier, Location loc)
9739 : base (identifier, loc)
9744 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9745 : base (identifier, args, loc)
9750 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9751 : base (identifier, arity, loc)
9756 public Expression LeftExpression {
9762 public override Location StartLocation {
9764 return expr == null ? loc : expr.StartLocation;
9768 protected override Expression DoResolve (ResolveContext rc)
9770 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9772 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9777 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9779 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9781 if (e is TypeExpr) {
9782 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9787 e = e.ResolveLValue (rc, rhs);
9792 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9794 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9795 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9797 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9800 public override bool HasConditionalAccess ()
9802 return LeftExpression.HasConditionalAccess ();
9805 public static bool IsValidDotExpression (TypeSpec type)
9807 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9808 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9810 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9813 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9815 var sn = expr as SimpleName;
9816 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9819 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9822 // Resolve expression which does have type set as we need expression type
9823 // with disable flow analysis as we don't know whether left side expression
9824 // is used as variable or type
9826 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9827 expr = expr.Resolve (rc);
9828 } else if (expr is TypeParameterExpr) {
9829 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9833 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9834 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9835 expr = expr.Resolve (rc, flags);
9838 expr = expr.Resolve (rc, flags);
9845 var ns = expr as NamespaceExpression;
9847 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9849 if (retval == null) {
9850 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9855 if (HasTypeArguments)
9856 return new GenericTypeExpr (retval.Type, targs, loc);
9858 targs.Resolve (rc, false);
9864 var cma = this as ConditionalMemberAccess;
9867 TypeSpec expr_type = expr.Type;
9868 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9869 me = expr as MemberExpr;
9871 me.ResolveInstanceExpression (rc, null);
9873 Arguments args = new Arguments (1);
9874 args.Add (new Argument (expr));
9877 return new DynamicConditionalMemberBinder (Name, args, loc);
9879 return new DynamicMemberBinder (Name, args, loc);
9883 if (!IsNullPropagatingValid (expr.Type)) {
9884 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9888 if (expr_type.IsNullableType) {
9889 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9890 expr_type = expr.Type;
9894 if (!IsValidDotExpression (expr_type)) {
9895 Error_OperatorCannotBeApplied (rc, expr_type);
9899 var lookup_arity = Arity;
9900 bool errorMode = false;
9901 Expression member_lookup;
9903 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9904 if (member_lookup == null) {
9906 // Try to look for extension method when member lookup failed
9908 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9909 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9910 if (methods != null) {
9911 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9912 if (HasTypeArguments) {
9913 if (!targs.Resolve (rc, false))
9916 emg.SetTypeArguments (rc, targs);
9920 emg.ConditionalAccess = true;
9922 // TODO: it should really skip the checks bellow
9923 return emg.Resolve (rc);
9929 if (member_lookup == null) {
9930 var dep = expr_type.GetMissingDependencies ();
9932 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9933 } else if (expr is TypeExpr) {
9934 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9936 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9942 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9943 // Leave it to overload resolution to report correct error
9944 } else if (!(member_lookup is TypeExpr)) {
9945 // TODO: rc.SymbolRelatedToPreviousError
9946 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9951 if (member_lookup != null)
9955 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9959 TypeExpr texpr = member_lookup as TypeExpr;
9960 if (texpr != null) {
9961 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9962 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9963 Name, texpr.GetSignatureForError ());
9966 if (!texpr.Type.IsAccessible (rc)) {
9967 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9968 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9972 if (HasTypeArguments) {
9973 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9976 return member_lookup;
9979 me = member_lookup as MemberExpr;
9981 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9986 me.ConditionalAccess = true;
9989 me = me.ResolveMemberAccess (rc, expr, sn);
9992 if (!targs.Resolve (rc, false))
9995 me.SetTypeArguments (rc, targs);
10001 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
10003 FullNamedExpression fexpr = expr as FullNamedExpression;
10004 if (fexpr == null) {
10005 expr.ResolveAsType (rc);
10009 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
10011 if (expr_resolved == null)
10014 var ns = expr_resolved as NamespaceExpression;
10016 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10018 if (retval == null) {
10019 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10020 } else if (Arity > 0) {
10021 if (HasTypeArguments) {
10022 retval = new GenericTypeExpr (retval.Type, targs, loc);
10023 if (retval.ResolveAsType (rc) == null)
10026 targs.Resolve (rc, allowUnboundTypeArguments);
10028 retval = new GenericOpenTypeExpr (retval.Type, loc);
10035 var tnew_expr = expr_resolved.ResolveAsType (rc);
10036 if (tnew_expr == null)
10039 TypeSpec expr_type = tnew_expr;
10040 if (TypeManager.IsGenericParameter (expr_type)) {
10041 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10042 tnew_expr.GetSignatureForError ());
10046 var qam = this as QualifiedAliasMember;
10048 rc.Module.Compiler.Report.Error (431, loc,
10049 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10054 TypeSpec nested = null;
10055 while (expr_type != null) {
10056 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10057 if (nested == null) {
10058 if (expr_type == tnew_expr) {
10059 Error_IdentifierNotFound (rc, expr_type);
10063 expr_type = tnew_expr;
10064 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10065 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10069 if (nested.IsAccessible (rc))
10073 // Keep looking after inaccessible candidate but only if
10074 // we are not in same context as the definition itself
10076 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10079 expr_type = expr_type.BaseType;
10084 if (HasTypeArguments) {
10085 texpr = new GenericTypeExpr (nested, targs, loc);
10087 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10089 texpr = new GenericOpenTypeExpr (nested, loc);
10091 } else if (expr_resolved is GenericOpenTypeExpr) {
10092 texpr = new GenericOpenTypeExpr (nested, loc);
10094 texpr = new TypeExpression (nested, loc);
10097 if (texpr.ResolveAsType (rc) == null)
10103 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10105 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10107 if (nested != null) {
10108 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10112 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10113 if (any_other_member != null) {
10114 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10118 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10119 Name, expr_type.GetSignatureForError ());
10122 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10124 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10127 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10129 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10130 ec.Report.SymbolRelatedToPreviousError (type);
10132 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10134 // a using directive or an assembly reference
10135 if (cand != null) {
10136 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10138 missing = "an assembly reference";
10141 ec.Report.Error (1061, loc,
10142 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10143 type.GetSignatureForError (), name, missing);
10147 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10150 public override string GetSignatureForError ()
10152 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10155 protected override void CloneTo (CloneContext clonectx, Expression t)
10157 MemberAccess target = (MemberAccess) t;
10159 target.expr = expr.Clone (clonectx);
10162 public override object Accept (StructuralVisitor visitor)
10164 return visitor.Visit (this);
10168 public class ConditionalMemberAccess : MemberAccess
10170 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10171 : base (expr, identifier, args, loc)
10175 public override bool HasConditionalAccess ()
10182 /// Implements checked expressions
10184 public class CheckedExpr : Expression {
10186 public Expression Expr;
10188 public CheckedExpr (Expression e, Location l)
10194 public override bool ContainsEmitWithAwait ()
10196 return Expr.ContainsEmitWithAwait ();
10199 public override Expression CreateExpressionTree (ResolveContext ec)
10201 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10202 return Expr.CreateExpressionTree (ec);
10205 protected override Expression DoResolve (ResolveContext ec)
10207 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10208 Expr = Expr.Resolve (ec);
10213 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10216 eclass = Expr.eclass;
10221 public override void Emit (EmitContext ec)
10223 using (ec.With (EmitContext.Options.CheckedScope, true))
10227 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10229 using (ec.With (EmitContext.Options.CheckedScope, true))
10230 Expr.EmitBranchable (ec, target, on_true);
10233 public override void FlowAnalysis (FlowAnalysisContext fc)
10235 Expr.FlowAnalysis (fc);
10238 public override SLE.Expression MakeExpression (BuilderContext ctx)
10240 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10241 return Expr.MakeExpression (ctx);
10245 protected override void CloneTo (CloneContext clonectx, Expression t)
10247 CheckedExpr target = (CheckedExpr) t;
10249 target.Expr = Expr.Clone (clonectx);
10252 public override object Accept (StructuralVisitor visitor)
10254 return visitor.Visit (this);
10259 /// Implements the unchecked expression
10261 public class UnCheckedExpr : Expression {
10263 public Expression Expr;
10265 public UnCheckedExpr (Expression e, Location l)
10271 public override bool ContainsEmitWithAwait ()
10273 return Expr.ContainsEmitWithAwait ();
10276 public override Expression CreateExpressionTree (ResolveContext ec)
10278 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10279 return Expr.CreateExpressionTree (ec);
10282 protected override Expression DoResolve (ResolveContext ec)
10284 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10285 Expr = Expr.Resolve (ec);
10290 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10293 eclass = Expr.eclass;
10298 public override void Emit (EmitContext ec)
10300 using (ec.With (EmitContext.Options.CheckedScope, false))
10304 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10306 using (ec.With (EmitContext.Options.CheckedScope, false))
10307 Expr.EmitBranchable (ec, target, on_true);
10310 public override void FlowAnalysis (FlowAnalysisContext fc)
10312 Expr.FlowAnalysis (fc);
10315 protected override void CloneTo (CloneContext clonectx, Expression t)
10317 UnCheckedExpr target = (UnCheckedExpr) t;
10319 target.Expr = Expr.Clone (clonectx);
10322 public override object Accept (StructuralVisitor visitor)
10324 return visitor.Visit (this);
10329 /// An Element Access expression.
10331 /// During semantic analysis these are transformed into
10332 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10334 public class ElementAccess : Expression
10336 public Arguments Arguments;
10337 public Expression Expr;
10338 bool conditional_access_receiver;
10340 public ElementAccess (Expression e, Arguments args, Location loc)
10344 this.Arguments = args;
10347 public bool ConditionalAccess { get; set; }
10349 public override Location StartLocation {
10351 return Expr.StartLocation;
10355 public override bool ContainsEmitWithAwait ()
10357 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10361 // We perform some simple tests, and then to "split" the emit and store
10362 // code we create an instance of a different class, and return that.
10364 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10366 if (conditionalAccessReceiver)
10367 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10369 Expr = Expr.Resolve (ec);
10371 if (conditionalAccessReceiver)
10372 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10379 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10380 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10384 if (type.IsArray) {
10385 var aa = new ArrayAccess (this, loc) {
10386 ConditionalAccess = ConditionalAccess,
10389 if (conditionalAccessReceiver)
10390 aa.SetConditionalAccessReceiver ();
10395 if (type.IsPointer)
10396 return Expr.MakePointerAccess (ec, type, Arguments);
10398 FieldExpr fe = Expr as FieldExpr;
10400 var ff = fe.Spec as FixedFieldSpec;
10402 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10406 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10407 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10408 var indexer = new IndexerExpr (indexers, type, this) {
10409 ConditionalAccess = ConditionalAccess
10412 if (conditionalAccessReceiver)
10413 indexer.SetConditionalAccessReceiver ();
10418 Error_CannotApplyIndexing (ec, type, loc);
10423 public override Expression CreateExpressionTree (ResolveContext ec)
10425 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10426 Expr.CreateExpressionTree (ec));
10428 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10431 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10433 if (type != InternalType.ErrorType) {
10434 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10435 type.GetSignatureForError ());
10439 public override bool HasConditionalAccess ()
10441 return ConditionalAccess || Expr.HasConditionalAccess ();
10444 void ResolveConditionalAccessReceiver (ResolveContext rc)
10446 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10447 conditional_access_receiver = true;
10451 protected override Expression DoResolve (ResolveContext rc)
10453 ResolveConditionalAccessReceiver (rc);
10455 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10459 return expr.Resolve (rc);
10462 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10464 var res = CreateAccessExpression (ec, false);
10468 return res.ResolveLValue (ec, rhs);
10471 public override void Emit (EmitContext ec)
10473 throw new Exception ("Should never be reached");
10476 public override void FlowAnalysis (FlowAnalysisContext fc)
10478 Expr.FlowAnalysis (fc);
10480 Arguments.FlowAnalysis (fc);
10483 public override string GetSignatureForError ()
10485 return Expr.GetSignatureForError ();
10488 protected override void CloneTo (CloneContext clonectx, Expression t)
10490 ElementAccess target = (ElementAccess) t;
10492 target.Expr = Expr.Clone (clonectx);
10493 if (Arguments != null)
10494 target.Arguments = Arguments.Clone (clonectx);
10497 public override object Accept (StructuralVisitor visitor)
10499 return visitor.Visit (this);
10504 /// Implements array access
10506 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10508 // Points to our "data" repository
10512 LocalTemporary temp;
10514 bool? has_await_args;
10515 bool conditional_access_receiver;
10517 public ArrayAccess (ElementAccess ea_data, Location l)
10523 public bool ConditionalAccess { get; set; }
10525 public void AddressOf (EmitContext ec, AddressOp mode)
10527 var ac = (ArrayContainer) ea.Expr.Type;
10529 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10530 LoadInstanceAndArguments (ec, false, true);
10533 LoadInstanceAndArguments (ec, false, false);
10535 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10536 ec.Emit (OpCodes.Readonly);
10538 ec.EmitArrayAddress (ac);
10541 public override Expression CreateExpressionTree (ResolveContext ec)
10543 if (ConditionalAccess)
10544 Error_NullShortCircuitInsideExpressionTree (ec);
10546 return ea.CreateExpressionTree (ec);
10549 public override bool ContainsEmitWithAwait ()
10551 return ea.ContainsEmitWithAwait ();
10554 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10556 if (HasConditionalAccess ())
10557 Error_NullPropagatingLValue (ec);
10559 return DoResolve (ec);
10562 protected override Expression DoResolve (ResolveContext ec)
10564 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10566 ea.Arguments.Resolve (ec, out dynamic);
10568 var ac = ea.Expr.Type as ArrayContainer;
10569 int rank = ea.Arguments.Count;
10570 if (ac.Rank != rank) {
10571 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10572 rank.ToString (), ac.Rank.ToString ());
10577 if (type.IsPointer) {
10578 if (ec.CurrentIterator != null) {
10579 UnsafeInsideIteratorError (ec, ea.Location);
10580 } else if (!ec.IsUnsafe) {
10581 UnsafeError (ec, ea.Location);
10585 if (conditional_access_receiver)
10586 type = LiftMemberType (ec, type);
10588 foreach (Argument a in ea.Arguments) {
10589 var na = a as NamedArgument;
10591 ElementAccess.Error_NamedArgument (na, ec.Report);
10593 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10596 eclass = ExprClass.Variable;
10601 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10603 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10606 public override void FlowAnalysis (FlowAnalysisContext fc)
10608 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10610 ea.FlowAnalysis (fc);
10612 if (conditional_access_receiver)
10613 fc.DefiniteAssignment = da;
10616 public override bool HasConditionalAccess ()
10618 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10622 // Load the array arguments into the stack.
10624 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10626 if (prepareAwait) {
10627 ea.Expr = ea.Expr.EmitToField (ec);
10629 var ie = new InstanceEmitter (ea.Expr, false);
10630 ie.Emit (ec, ConditionalAccess);
10632 if (duplicateArguments) {
10633 ec.Emit (OpCodes.Dup);
10635 var copy = new LocalTemporary (ea.Expr.Type);
10641 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10642 if (dup_args != null)
10643 ea.Arguments = dup_args;
10646 public void Emit (EmitContext ec, bool leave_copy)
10649 ec.EmitLoadFromPtr (type);
10651 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10652 LoadInstanceAndArguments (ec, false, true);
10655 if (conditional_access_receiver)
10656 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10658 var ac = (ArrayContainer) ea.Expr.Type;
10659 LoadInstanceAndArguments (ec, false, false);
10660 ec.EmitArrayLoad (ac);
10662 if (conditional_access_receiver)
10663 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10667 ec.Emit (OpCodes.Dup);
10668 temp = new LocalTemporary (this.type);
10673 public override void Emit (EmitContext ec)
10678 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10680 var ac = (ArrayContainer) ea.Expr.Type;
10681 TypeSpec t = source.Type;
10683 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10686 // When we are dealing with a struct, get the address of it to avoid value copy
10687 // Same cannot be done for reference type because array covariance and the
10688 // check in ldelema requires to specify the type of array element stored at the index
10690 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10691 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10693 if (has_await_args.Value) {
10694 if (source.ContainsEmitWithAwait ()) {
10695 source = source.EmitToField (ec);
10696 isCompound = false;
10700 LoadInstanceAndArguments (ec, isCompound, false);
10705 ec.EmitArrayAddress (ac);
10708 ec.Emit (OpCodes.Dup);
10712 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10714 if (has_await_args.Value) {
10715 if (source.ContainsEmitWithAwait ())
10716 source = source.EmitToField (ec);
10718 LoadInstanceAndArguments (ec, false, false);
10725 var lt = ea.Expr as LocalTemporary;
10731 ec.Emit (OpCodes.Dup);
10732 temp = new LocalTemporary (this.type);
10737 ec.EmitStoreFromPtr (t);
10739 ec.EmitArrayStore (ac);
10742 if (temp != null) {
10748 public override Expression EmitToField (EmitContext ec)
10751 // Have to be specialized for arrays to get access to
10752 // underlying element. Instead of another result copy we
10753 // need direct access to element
10757 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10759 ea.Expr = ea.Expr.EmitToField (ec);
10760 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10764 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10766 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10769 public override SLE.Expression MakeExpression (BuilderContext ctx)
10771 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10774 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10776 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10777 return Arguments.MakeExpression (ea.Arguments, ctx);
10781 public void SetConditionalAccessReceiver ()
10783 conditional_access_receiver = true;
10788 // Indexer access expression
10790 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10792 IList<MemberSpec> indexers;
10793 Arguments arguments;
10794 TypeSpec queried_type;
10796 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10797 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10801 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10804 this.indexers = indexers;
10805 this.queried_type = queriedType;
10806 this.InstanceExpression = instance;
10807 this.arguments = args;
10812 protected override Arguments Arguments {
10821 protected override TypeSpec DeclaringType {
10823 return best_candidate.DeclaringType;
10827 public override bool IsInstance {
10833 public override bool IsStatic {
10839 public override string KindName {
10840 get { return "indexer"; }
10843 public override string Name {
10851 public override bool ContainsEmitWithAwait ()
10853 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10856 public override Expression CreateExpressionTree (ResolveContext ec)
10858 if (ConditionalAccess) {
10859 Error_NullShortCircuitInsideExpressionTree (ec);
10862 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10863 InstanceExpression.CreateExpressionTree (ec),
10864 new TypeOfMethod (Getter, loc));
10866 return CreateExpressionFactoryCall (ec, "Call", args);
10869 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10871 LocalTemporary await_source_arg = null;
10874 emitting_compound_assignment = true;
10875 if (source is DynamicExpressionStatement) {
10880 emitting_compound_assignment = false;
10882 if (has_await_arguments) {
10883 await_source_arg = new LocalTemporary (Type);
10884 await_source_arg.Store (ec);
10886 arguments.Add (new Argument (await_source_arg));
10889 temp = await_source_arg;
10892 has_await_arguments = false;
10897 ec.Emit (OpCodes.Dup);
10898 temp = new LocalTemporary (Type);
10904 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10905 source = source.EmitToField (ec);
10907 temp = new LocalTemporary (Type);
10914 arguments.Add (new Argument (source));
10917 var call = new CallEmitter ();
10918 call.InstanceExpression = InstanceExpression;
10919 if (arguments == null)
10920 call.InstanceExpressionOnStack = true;
10922 call.Emit (ec, Setter, arguments, loc);
10924 if (temp != null) {
10927 } else if (leave_copy) {
10931 if (await_source_arg != null) {
10932 await_source_arg.Release (ec);
10936 public override void FlowAnalysis (FlowAnalysisContext fc)
10938 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10940 base.FlowAnalysis (fc);
10941 arguments.FlowAnalysis (fc);
10943 if (conditional_access_receiver)
10944 fc.DefiniteAssignment = da;
10947 public override string GetSignatureForError ()
10949 return best_candidate.GetSignatureForError ();
10952 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10955 throw new NotSupportedException ();
10957 var value = new[] { source.MakeExpression (ctx) };
10958 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10959 return SLE.Expression.Block (
10960 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10965 public override SLE.Expression MakeExpression (BuilderContext ctx)
10968 return base.MakeExpression (ctx);
10970 var args = Arguments.MakeExpression (arguments, ctx);
10971 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10975 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10977 if (best_candidate != null)
10980 eclass = ExprClass.IndexerAccess;
10983 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10984 arguments.Resolve (rc, out dynamic);
10987 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10990 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10991 res.BaseMembersProvider = this;
10992 res.InstanceQualifier = this;
10994 // TODO: Do I need 2 argument sets?
10995 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10996 if (best_candidate != null)
10997 type = res.BestCandidateReturnType;
10998 else if (!res.BestCandidateIsDynamic)
11003 // It has dynamic arguments
11006 Arguments args = new Arguments (arguments.Count + 1);
11008 rc.Report.Error (1972, loc,
11009 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
11011 args.Add (new Argument (InstanceExpression));
11013 args.AddRange (arguments);
11015 best_candidate = null;
11016 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11020 // Try to avoid resolving left expression again
11022 if (right_side != null)
11023 ResolveInstanceExpression (rc, right_side);
11028 protected override void CloneTo (CloneContext clonectx, Expression t)
11030 IndexerExpr target = (IndexerExpr) t;
11032 if (arguments != null)
11033 target.arguments = arguments.Clone (clonectx);
11036 public void SetConditionalAccessReceiver ()
11038 conditional_access_receiver = true;
11041 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11043 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11046 #region IBaseMembersProvider Members
11048 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11050 var baseType = type.BaseType;
11051 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11053 if (members == null && !type.IsInterface) {
11054 var tps = queried_type as TypeParameterSpec;
11056 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11062 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11064 if (queried_type == member.DeclaringType)
11067 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11068 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11071 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11080 // A base access expression
11082 public class BaseThis : This
11084 public BaseThis (Location loc)
11089 public BaseThis (TypeSpec type, Location loc)
11093 eclass = ExprClass.Variable;
11098 public override string Name {
11106 public override Expression CreateExpressionTree (ResolveContext ec)
11108 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11109 return base.CreateExpressionTree (ec);
11112 public override void Emit (EmitContext ec)
11116 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11117 var context_type = ec.CurrentType;
11118 ec.Emit (OpCodes.Ldobj, context_type);
11119 ec.Emit (OpCodes.Box, context_type);
11123 protected override void Error_ThisNotAvailable (ResolveContext ec)
11126 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11128 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11132 public override void ResolveBase (ResolveContext ec)
11134 base.ResolveBase (ec);
11135 type = ec.CurrentType.BaseType;
11138 public override object Accept (StructuralVisitor visitor)
11140 return visitor.Visit (this);
11145 /// This class exists solely to pass the Type around and to be a dummy
11146 /// that can be passed to the conversion functions (this is used by
11147 /// foreach implementation to typecast the object return value from
11148 /// get_Current into the proper type. All code has been generated and
11149 /// we only care about the side effect conversions to be performed
11151 /// This is also now used as a placeholder where a no-action expression
11152 /// is needed (the `New' class).
11154 public class EmptyExpression : Expression
11156 sealed class OutAccessExpression : EmptyExpression
11158 public OutAccessExpression (TypeSpec t)
11163 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11165 rc.Report.Error (206, right_side.Location,
11166 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11172 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11173 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11174 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11175 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11176 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11177 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11178 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11179 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11181 public EmptyExpression (TypeSpec t)
11184 eclass = ExprClass.Value;
11185 loc = Location.Null;
11188 protected override void CloneTo (CloneContext clonectx, Expression target)
11192 public override bool ContainsEmitWithAwait ()
11197 public override Expression CreateExpressionTree (ResolveContext ec)
11199 throw new NotSupportedException ("ET");
11202 protected override Expression DoResolve (ResolveContext ec)
11207 public override void Emit (EmitContext ec)
11209 // nothing, as we only exist to not do anything.
11212 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11216 public override void EmitSideEffect (EmitContext ec)
11220 public override object Accept (StructuralVisitor visitor)
11222 return visitor.Visit (this);
11226 sealed class EmptyAwaitExpression : EmptyExpression
11228 public EmptyAwaitExpression (TypeSpec type)
11233 public override bool ContainsEmitWithAwait ()
11240 // Empty statement expression
11242 public sealed class EmptyExpressionStatement : ExpressionStatement
11244 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11246 private EmptyExpressionStatement ()
11248 loc = Location.Null;
11251 public override bool ContainsEmitWithAwait ()
11256 public override Expression CreateExpressionTree (ResolveContext ec)
11261 public override void EmitStatement (EmitContext ec)
11266 protected override Expression DoResolve (ResolveContext ec)
11268 eclass = ExprClass.Value;
11269 type = ec.BuiltinTypes.Object;
11273 public override void Emit (EmitContext ec)
11278 public override object Accept (StructuralVisitor visitor)
11280 return visitor.Visit (this);
11284 public class ErrorExpression : EmptyExpression
11286 public static readonly ErrorExpression Instance = new ErrorExpression ();
11288 private ErrorExpression ()
11289 : base (InternalType.ErrorType)
11293 public override Expression CreateExpressionTree (ResolveContext ec)
11298 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11303 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11307 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11311 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11315 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11319 public override object Accept (StructuralVisitor visitor)
11321 return visitor.Visit (this);
11325 public class UserCast : Expression {
11329 public UserCast (MethodSpec method, Expression source, Location l)
11331 if (source == null)
11332 throw new ArgumentNullException ("source");
11334 this.method = method;
11335 this.source = source;
11336 type = method.ReturnType;
11340 public Expression Source {
11349 public override bool ContainsEmitWithAwait ()
11351 return source.ContainsEmitWithAwait ();
11354 public override Expression CreateExpressionTree (ResolveContext ec)
11356 Arguments args = new Arguments (3);
11357 args.Add (new Argument (source.CreateExpressionTree (ec)));
11358 args.Add (new Argument (new TypeOf (type, loc)));
11359 args.Add (new Argument (new TypeOfMethod (method, loc)));
11360 return CreateExpressionFactoryCall (ec, "Convert", args);
11363 protected override Expression DoResolve (ResolveContext ec)
11365 method.CheckObsoleteness (ec, source.Location);
11367 eclass = ExprClass.Value;
11371 public override void Emit (EmitContext ec)
11374 ec.MarkCallEntry (loc);
11375 ec.Emit (OpCodes.Call, method);
11378 public override void FlowAnalysis (FlowAnalysisContext fc)
11380 source.FlowAnalysis (fc);
11383 public override string GetSignatureForError ()
11385 return TypeManager.CSharpSignature (method);
11388 public override SLE.Expression MakeExpression (BuilderContext ctx)
11391 return base.MakeExpression (ctx);
11393 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11399 // Holds additional type specifiers like ?, *, []
11401 public class ComposedTypeSpecifier
11403 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11405 public readonly int Dimension;
11406 public readonly Location Location;
11408 public ComposedTypeSpecifier (int specifier, Location loc)
11410 this.Dimension = specifier;
11411 this.Location = loc;
11415 public bool IsNullable {
11417 return Dimension == -1;
11421 public bool IsPointer {
11423 return Dimension == -2;
11427 public ComposedTypeSpecifier Next { get; set; }
11431 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11433 return new ComposedTypeSpecifier (dimension, loc);
11436 public static ComposedTypeSpecifier CreateNullable (Location loc)
11438 return new ComposedTypeSpecifier (-1, loc);
11441 public static ComposedTypeSpecifier CreatePointer (Location loc)
11443 return new ComposedTypeSpecifier (-2, loc);
11446 public string GetSignatureForError ()
11451 ArrayContainer.GetPostfixSignature (Dimension);
11453 return Next != null ? s + Next.GetSignatureForError () : s;
11458 // This class is used to "construct" the type during a typecast
11459 // operation. Since the Type.GetType class in .NET can parse
11460 // the type specification, we just use this to construct the type
11461 // one bit at a time.
11463 public class ComposedCast : TypeExpr {
11464 FullNamedExpression left;
11465 ComposedTypeSpecifier spec;
11467 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11470 throw new ArgumentNullException ("spec");
11474 this.loc = left.Location;
11477 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11479 type = left.ResolveAsType (ec);
11483 eclass = ExprClass.Type;
11485 var single_spec = spec;
11487 if (single_spec.IsNullable) {
11488 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11492 single_spec = single_spec.Next;
11493 } else if (single_spec.IsPointer) {
11495 // Declared fields cannot have unmanaged check done before all types are defined
11497 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11500 var rc = ec as ResolveContext;
11501 if (rc?.CurrentIterator != null) {
11502 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11503 } else if (!ec.IsUnsafe) {
11504 UnsafeError (ec.Module.Compiler.Report, loc);
11508 type = PointerContainer.MakeType (ec.Module, type);
11509 single_spec = single_spec.Next;
11510 } while (single_spec != null && single_spec.IsPointer);
11513 if (single_spec != null && single_spec.Dimension > 0) {
11514 if (type.IsSpecialRuntimeType) {
11515 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11516 } else if (type.IsStatic) {
11517 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11518 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11519 type.GetSignatureForError ());
11521 MakeArray (ec.Module, single_spec);
11528 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11530 if (spec.Next != null)
11531 MakeArray (module, spec.Next);
11533 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11536 public override string GetSignatureForError ()
11538 return left.GetSignatureForError () + spec.GetSignatureForError ();
11541 public override object Accept (StructuralVisitor visitor)
11543 return visitor.Visit (this);
11547 class FixedBufferPtr : Expression
11549 readonly Expression array;
11551 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11553 this.type = array_type;
11554 this.array = array;
11558 public override bool ContainsEmitWithAwait ()
11560 throw new NotImplementedException ();
11563 public override Expression CreateExpressionTree (ResolveContext ec)
11565 Error_PointerInsideExpressionTree (ec);
11569 public override void Emit(EmitContext ec)
11574 protected override Expression DoResolve (ResolveContext ec)
11576 type = PointerContainer.MakeType (ec.Module, type);
11577 eclass = ExprClass.Value;
11584 // This class is used to represent the address of an array, used
11585 // only by the Fixed statement, this generates "&a [0]" construct
11586 // for fixed (char *pa = a)
11588 class ArrayPtr : FixedBufferPtr
11590 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11591 base (array, array_type, l)
11595 public override void Emit (EmitContext ec)
11600 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11605 // Encapsulates a conversion rules required for array indexes
11607 public class ArrayIndexCast : TypeCast
11609 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11610 : base (expr, returnType)
11612 if (expr.Type == returnType) // int -> int
11613 throw new ArgumentException ("unnecessary array index conversion");
11616 public override Expression CreateExpressionTree (ResolveContext ec)
11618 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11619 return base.CreateExpressionTree (ec);
11623 public override void Emit (EmitContext ec)
11627 switch (child.Type.BuiltinType) {
11628 case BuiltinTypeSpec.Type.UInt:
11629 ec.Emit (OpCodes.Conv_U);
11631 case BuiltinTypeSpec.Type.Long:
11632 ec.Emit (OpCodes.Conv_Ovf_I);
11634 case BuiltinTypeSpec.Type.ULong:
11635 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11638 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11644 // Implements the `stackalloc' keyword
11646 public class StackAlloc : Expression {
11651 public StackAlloc (Expression type, Expression count, Location l)
11654 this.count = count;
11658 public Expression TypeExpression {
11664 public Expression CountExpression {
11670 public override bool ContainsEmitWithAwait ()
11675 public override Expression CreateExpressionTree (ResolveContext ec)
11677 throw new NotSupportedException ("ET");
11680 protected override Expression DoResolve (ResolveContext ec)
11682 count = count.Resolve (ec);
11686 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11687 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11692 Constant c = count as Constant;
11693 if (c != null && c.IsNegative) {
11694 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11697 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11698 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11701 otype = texpr.ResolveAsType (ec);
11705 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11708 type = PointerContainer.MakeType (ec.Module, otype);
11709 eclass = ExprClass.Value;
11714 public override void Emit (EmitContext ec)
11716 int size = BuiltinTypeSpec.GetSize (otype);
11721 ec.Emit (OpCodes.Sizeof, otype);
11725 ec.Emit (OpCodes.Mul_Ovf_Un);
11726 ec.Emit (OpCodes.Localloc);
11729 protected override void CloneTo (CloneContext clonectx, Expression t)
11731 StackAlloc target = (StackAlloc) t;
11732 target.count = count.Clone (clonectx);
11733 target.texpr = texpr.Clone (clonectx);
11736 public override object Accept (StructuralVisitor visitor)
11738 return visitor.Visit (this);
11743 // An object initializer expression
11745 public class ElementInitializer : Assign
11747 public readonly string Name;
11749 public ElementInitializer (string name, Expression initializer, Location loc)
11750 : base (null, initializer, loc)
11755 public bool IsDictionaryInitializer {
11757 return Name == null;
11761 protected override void CloneTo (CloneContext clonectx, Expression t)
11763 ElementInitializer target = (ElementInitializer) t;
11764 target.source = source.Clone (clonectx);
11767 public override Expression CreateExpressionTree (ResolveContext ec)
11769 Arguments args = new Arguments (2);
11770 FieldExpr fe = target as FieldExpr;
11772 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11774 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11777 Expression arg_expr;
11778 var cinit = source as CollectionOrObjectInitializers;
11779 if (cinit == null) {
11781 arg_expr = source.CreateExpressionTree (ec);
11783 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11784 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11787 args.Add (new Argument (arg_expr));
11788 return CreateExpressionFactoryCall (ec, mname, args);
11791 protected override Expression DoResolve (ResolveContext ec)
11793 if (source == null)
11794 return EmptyExpressionStatement.Instance;
11796 if (!ResolveElement (ec))
11799 if (source is CollectionOrObjectInitializers) {
11800 target = target.Resolve (ec);
11801 if (target == null)
11804 Expression previous = ec.CurrentInitializerVariable;
11805 ec.CurrentInitializerVariable = target;
11806 source = source.Resolve (ec);
11807 ec.CurrentInitializerVariable = previous;
11808 if (source == null)
11811 eclass = source.eclass;
11812 type = source.Type;
11817 return base.DoResolve (ec);
11820 public override void EmitStatement (EmitContext ec)
11822 if (source is CollectionOrObjectInitializers)
11825 base.EmitStatement (ec);
11828 protected virtual bool ResolveElement (ResolveContext rc)
11830 var t = rc.CurrentInitializerVariable.Type;
11831 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11832 Arguments args = new Arguments (1);
11833 args.Add (new Argument (rc.CurrentInitializerVariable));
11834 target = new DynamicMemberBinder (Name, args, loc);
11836 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11837 if (member == null) {
11838 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11840 if (member != null) {
11841 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11842 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11847 if (member == null) {
11848 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11852 var me = member as MemberExpr;
11853 if (me is EventExpr) {
11854 me = me.ResolveMemberAccess (rc, null, null);
11855 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11856 rc.Report.Error (1913, loc,
11857 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11858 member.GetSignatureForError ());
11864 rc.Report.Error (1914, loc,
11865 "Static field or property `{0}' cannot be assigned in an object initializer",
11866 me.GetSignatureForError ());
11870 me.InstanceExpression = rc.CurrentInitializerVariable;
11878 // A collection initializer expression
11880 class CollectionElementInitializer : Invocation
11882 public class ElementInitializerArgument : Argument
11884 public ElementInitializerArgument (Expression e)
11890 sealed class AddMemberAccess : MemberAccess
11892 public AddMemberAccess (Expression expr, Location loc)
11893 : base (expr, "Add", loc)
11897 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11899 if (TypeManager.HasElementType (type))
11902 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11906 public CollectionElementInitializer (Expression argument)
11907 : base (null, new Arguments (1))
11909 base.arguments.Add (new ElementInitializerArgument (argument));
11910 this.loc = argument.Location;
11913 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11914 : base (null, new Arguments (arguments.Count))
11916 foreach (Expression e in arguments)
11917 base.arguments.Add (new ElementInitializerArgument (e));
11922 public CollectionElementInitializer (Location loc)
11923 : base (null, null)
11928 public override Expression CreateExpressionTree (ResolveContext ec)
11930 Arguments args = new Arguments (2);
11931 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11933 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11934 foreach (Argument a in arguments) {
11935 if (a.ArgType == Argument.AType.ExtensionType) {
11936 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11939 expr_initializers.Add (a.CreateExpressionTree (ec));
11942 args.Add (new Argument (new ArrayCreation (
11943 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11944 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11947 protected override void CloneTo (CloneContext clonectx, Expression t)
11949 CollectionElementInitializer target = (CollectionElementInitializer) t;
11950 if (arguments != null)
11951 target.arguments = arguments.Clone (clonectx);
11954 protected override Expression DoResolve (ResolveContext ec)
11956 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11958 return base.DoResolve (ec);
11962 class DictionaryElementInitializer : ElementInitializer
11964 readonly Arguments args;
11966 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11967 : base (null, initializer, loc)
11969 this.args = arguments;
11972 public override Expression CreateExpressionTree (ResolveContext ec)
11974 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11978 protected override bool ResolveElement (ResolveContext rc)
11980 var init = rc.CurrentInitializerVariable;
11981 var type = init.Type;
11983 if (type.IsArray) {
11984 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11988 if (type.IsPointer) {
11989 target = init.MakePointerAccess (rc, type, args);
11993 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11994 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11995 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11999 target = new IndexerExpr (indexers, type, init, args, loc);
12005 // A block of object or collection initializers
12007 public class CollectionOrObjectInitializers : ExpressionStatement
12009 IList<Expression> initializers;
12010 bool is_collection_initialization;
12012 public CollectionOrObjectInitializers (Location loc)
12013 : this (new Expression[0], loc)
12017 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12019 this.initializers = initializers;
12023 public IList<Expression> Initializers {
12025 return initializers;
12029 public bool IsEmpty {
12031 return initializers.Count == 0;
12035 public bool IsCollectionInitializer {
12037 return is_collection_initialization;
12041 protected override void CloneTo (CloneContext clonectx, Expression target)
12043 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12045 t.initializers = new List<Expression> (initializers.Count);
12046 foreach (var e in initializers)
12047 t.initializers.Add (e.Clone (clonectx));
12050 public override bool ContainsEmitWithAwait ()
12052 foreach (var e in initializers) {
12053 if (e.ContainsEmitWithAwait ())
12060 public override Expression CreateExpressionTree (ResolveContext ec)
12062 return CreateExpressionTree (ec, false);
12065 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12067 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12068 foreach (Expression e in initializers) {
12069 Expression expr = e.CreateExpressionTree (ec);
12071 expr_initializers.Add (expr);
12075 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12077 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12080 protected override Expression DoResolve (ResolveContext ec)
12082 List<string> element_names = null;
12083 for (int i = 0; i < initializers.Count; ++i) {
12084 Expression initializer = initializers [i];
12085 ElementInitializer element_initializer = initializer as ElementInitializer;
12088 if (element_initializer != null) {
12089 element_names = new List<string> (initializers.Count);
12090 if (!element_initializer.IsDictionaryInitializer)
12091 element_names.Add (element_initializer.Name);
12092 } else if (initializer is CompletingExpression) {
12093 initializer.Resolve (ec);
12094 throw new InternalErrorException ("This line should never be reached");
12096 var t = ec.CurrentInitializerVariable.Type;
12097 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12098 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12099 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12100 "object initializer because type `{1}' does not implement `{2}' interface",
12101 ec.CurrentInitializerVariable.GetSignatureForError (),
12102 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12103 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12106 is_collection_initialization = true;
12109 if (is_collection_initialization != (element_initializer == null)) {
12110 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12111 is_collection_initialization ? "collection initializer" : "object initializer");
12115 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12116 if (element_names.Contains (element_initializer.Name)) {
12117 ec.Report.Error (1912, element_initializer.Location,
12118 "An object initializer includes more than one member `{0}' initialization",
12119 element_initializer.Name);
12121 element_names.Add (element_initializer.Name);
12126 Expression e = initializer.Resolve (ec);
12127 if (e == EmptyExpressionStatement.Instance)
12128 initializers.RemoveAt (i--);
12130 initializers [i] = e;
12133 type = ec.CurrentInitializerVariable.Type;
12134 if (is_collection_initialization) {
12135 if (TypeManager.HasElementType (type)) {
12136 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12137 type.GetSignatureForError ());
12141 eclass = ExprClass.Variable;
12145 public override void Emit (EmitContext ec)
12147 EmitStatement (ec);
12150 public override void EmitStatement (EmitContext ec)
12152 foreach (ExpressionStatement e in initializers) {
12153 // TODO: need location region
12154 ec.Mark (e.Location);
12155 e.EmitStatement (ec);
12159 public override void FlowAnalysis (FlowAnalysisContext fc)
12161 foreach (var initializer in initializers) {
12162 if (initializer != null)
12163 initializer.FlowAnalysis (fc);
12169 // New expression with element/object initializers
12171 public class NewInitialize : New
12174 // This class serves as a proxy for variable initializer target instances.
12175 // A real variable is assigned later when we resolve left side of an
12178 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12180 NewInitialize new_instance;
12182 public InitializerTargetExpression (NewInitialize newInstance)
12184 this.type = newInstance.type;
12185 this.loc = newInstance.loc;
12186 this.eclass = newInstance.eclass;
12187 this.new_instance = newInstance;
12190 public override bool ContainsEmitWithAwait ()
12195 public override Expression CreateExpressionTree (ResolveContext ec)
12197 // Should not be reached
12198 throw new NotSupportedException ("ET");
12201 protected override Expression DoResolve (ResolveContext ec)
12206 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12211 public override void Emit (EmitContext ec)
12213 Expression e = (Expression) new_instance.instance;
12217 public override Expression EmitToField (EmitContext ec)
12219 return (Expression) new_instance.instance;
12222 #region IMemoryLocation Members
12224 public void AddressOf (EmitContext ec, AddressOp mode)
12226 new_instance.instance.AddressOf (ec, mode);
12232 CollectionOrObjectInitializers initializers;
12233 IMemoryLocation instance;
12234 DynamicExpressionStatement dynamic;
12236 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12237 : base (requested_type, arguments, l)
12239 this.initializers = initializers;
12242 public CollectionOrObjectInitializers Initializers {
12244 return initializers;
12248 protected override void CloneTo (CloneContext clonectx, Expression t)
12250 base.CloneTo (clonectx, t);
12252 NewInitialize target = (NewInitialize) t;
12253 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12256 public override bool ContainsEmitWithAwait ()
12258 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12261 public override Expression CreateExpressionTree (ResolveContext ec)
12263 Arguments args = new Arguments (2);
12264 args.Add (new Argument (base.CreateExpressionTree (ec)));
12265 if (!initializers.IsEmpty)
12266 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12268 return CreateExpressionFactoryCall (ec,
12269 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12273 protected override Expression DoResolve (ResolveContext rc)
12275 Expression e = base.DoResolve (rc);
12279 if (type.IsDelegate) {
12280 rc.Report.Error (1958, Initializers.Location,
12281 "Object and collection initializers cannot be used to instantiate a delegate");
12284 Expression previous = rc.CurrentInitializerVariable;
12285 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12286 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12287 initializers.Resolve (rc);
12289 rc.CurrentInitializerVariable = previous;
12291 dynamic = e as DynamicExpressionStatement;
12292 if (dynamic != null)
12298 public override void Emit (EmitContext ec)
12300 if (!CanEmitOptimizedLocalTarget (ec)) {
12301 var fe = ec.GetTemporaryField (type);
12303 if (!Emit (ec, fe))
12312 public override bool Emit (EmitContext ec, IMemoryLocation target)
12315 // Expression is initialized into temporary target then moved
12316 // to real one for atomicity
12318 IMemoryLocation temp_target = target;
12320 LocalTemporary temp = null;
12321 bool by_ref = false;
12322 if (!initializers.IsEmpty) {
12323 temp_target = target as LocalTemporary;
12324 if (temp_target == null)
12325 temp_target = target as StackFieldExpr;
12327 if (temp_target == null) {
12328 var vr = target as VariableReference;
12329 if (vr != null && vr.IsRef) {
12335 if (temp_target == null)
12336 temp_target = temp = new LocalTemporary (type);
12339 bool left_on_stack;
12340 if (dynamic != null) {
12342 left_on_stack = true;
12344 left_on_stack = base.Emit (ec, temp_target);
12347 if (initializers.IsEmpty)
12348 return left_on_stack;
12350 StackFieldExpr sf = null;
12352 // Move a new instance (reference-type) to local temporary variable
12353 if (left_on_stack) {
12355 temp_target = temp = new LocalTemporary (type);
12361 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12363 throw new NotImplementedException ();
12365 sf = ec.GetTemporaryField (type);
12366 sf.AutomaticallyReuse = false;
12367 sf.EmitAssign (ec, temp, false, false);
12370 left_on_stack = false;
12374 instance = temp_target;
12376 initializers.Emit (ec);
12378 ((Expression)temp_target).Emit (ec);
12384 sf.PrepareCleanup (ec);
12389 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12391 return !(method == null && TypeSpec.IsValueType (type) &&
12392 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12393 initializers.ContainsEmitWithAwait ());
12396 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12398 instance = base.EmitAddressOf (ec, Mode);
12400 if (!initializers.IsEmpty)
12401 initializers.Emit (ec);
12406 public override void FlowAnalysis (FlowAnalysisContext fc)
12408 base.FlowAnalysis (fc);
12409 initializers.FlowAnalysis (fc);
12412 public override object Accept (StructuralVisitor visitor)
12414 return visitor.Visit (this);
12418 public class NewAnonymousType : New
12420 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12422 List<AnonymousTypeParameter> parameters;
12423 readonly TypeContainer parent;
12424 AnonymousTypeClass anonymous_type;
12426 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12427 : base (null, null, loc)
12429 this.parameters = parameters;
12430 this.parent = parent;
12433 public List<AnonymousTypeParameter> Parameters {
12435 return this.parameters;
12439 protected override void CloneTo (CloneContext clonectx, Expression target)
12441 if (parameters == null)
12444 NewAnonymousType t = (NewAnonymousType) target;
12445 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12446 foreach (AnonymousTypeParameter atp in parameters)
12447 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12450 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12452 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12456 type = AnonymousTypeClass.Create (parent, parameters, loc);
12460 int errors = ec.Report.Errors;
12461 type.CreateContainer ();
12462 type.DefineContainer ();
12463 type.ExpandBaseInterfaces ();
12465 if ((ec.Report.Errors - errors) == 0) {
12466 parent.Module.AddAnonymousType (type);
12467 type.PrepareEmit ();
12473 public override Expression CreateExpressionTree (ResolveContext ec)
12475 if (parameters == null)
12476 return base.CreateExpressionTree (ec);
12478 var init = new ArrayInitializer (parameters.Count, loc);
12479 foreach (var m in anonymous_type.Members) {
12480 var p = m as Property;
12482 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12485 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12486 foreach (Argument a in arguments)
12487 ctor_args.Add (a.CreateExpressionTree (ec));
12489 Arguments args = new Arguments (3);
12490 args.Add (new Argument (new TypeOfMethod (method, loc)));
12491 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12492 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12494 return CreateExpressionFactoryCall (ec, "New", args);
12497 protected override Expression DoResolve (ResolveContext ec)
12499 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12500 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12504 if (parameters == null) {
12505 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12506 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12507 return base.DoResolve (ec);
12510 bool error = false;
12511 arguments = new Arguments (parameters.Count);
12512 var t_args = new TypeSpec [parameters.Count];
12513 for (int i = 0; i < parameters.Count; ++i) {
12514 Expression e = parameters [i].Resolve (ec);
12520 arguments.Add (new Argument (e));
12521 t_args [i] = e.Type;
12527 anonymous_type = CreateAnonymousType (ec, parameters);
12528 if (anonymous_type == null)
12531 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12532 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12533 eclass = ExprClass.Value;
12537 public override object Accept (StructuralVisitor visitor)
12539 return visitor.Visit (this);
12543 public class AnonymousTypeParameter : ShimExpression
12545 public readonly string Name;
12547 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12548 : base (initializer)
12554 public AnonymousTypeParameter (Parameter parameter)
12555 : base (new SimpleName (parameter.Name, parameter.Location))
12557 this.Name = parameter.Name;
12558 this.loc = parameter.Location;
12561 public override bool Equals (object o)
12563 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12564 return other != null && Name == other.Name;
12567 public override int GetHashCode ()
12569 return Name.GetHashCode ();
12572 protected override Expression DoResolve (ResolveContext ec)
12574 Expression e = expr.Resolve (ec);
12578 if (e.eclass == ExprClass.MethodGroup) {
12579 Error_InvalidInitializer (ec, e.ExprClassName);
12584 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
12585 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12592 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12594 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12595 Name, initializer);
12599 public class CatchFilterExpression : BooleanExpression
12601 public CatchFilterExpression (Expression expr, Location loc)
12608 public class InterpolatedString : Expression
12610 readonly StringLiteral start, end;
12611 List<Expression> interpolations;
12612 Arguments arguments;
12614 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12616 this.start = start;
12618 this.interpolations = interpolations;
12619 loc = start.Location;
12622 protected override void CloneTo (CloneContext clonectx, Expression t)
12624 InterpolatedString target = (InterpolatedString) t;
12626 if (interpolations != null) {
12627 target.interpolations = new List<Expression> ();
12628 foreach (var interpolation in interpolations) {
12629 target.interpolations.Add (interpolation.Clone (clonectx));
12634 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12636 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12637 if (factory == null)
12640 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12641 var res = new Invocation (ma, arguments).Resolve (rc);
12642 if (res != null && res.Type != type)
12643 res = Convert.ExplicitConversion (rc, res, type, loc);
12648 public override bool ContainsEmitWithAwait ()
12650 if (interpolations == null)
12653 foreach (var expr in interpolations) {
12654 if (expr.ContainsEmitWithAwait ())
12661 public override Expression CreateExpressionTree (ResolveContext rc)
12663 var best = ResolveBestFormatOverload (rc);
12667 Expression instance = new NullLiteral (loc);
12668 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12669 return CreateExpressionFactoryCall (rc, "Call", args);
12672 protected override Expression DoResolve (ResolveContext rc)
12676 if (interpolations == null) {
12678 arguments = new Arguments (1);
12680 arguments = new Arguments (interpolations.Count);
12682 var sb = new StringBuilder (start.Value);
12683 for (int i = 0; i < interpolations.Count; ++i) {
12685 sb.Append ('{').Append (i / 2);
12686 var isi = (InterpolatedStringInsert)interpolations [i];
12687 if (isi.Alignment != null) {
12689 var value = isi.ResolveAligment (rc);
12691 sb.Append (value.Value);
12694 if (isi.Format != null) {
12696 sb.Append (isi.Format);
12700 arguments.Add (new Argument (isi.Resolve (rc)));
12702 sb.Append (((StringLiteral)interpolations [i]).Value);
12706 sb.Append (end.Value);
12707 str = sb.ToString ();
12710 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12712 eclass = ExprClass.Value;
12713 type = rc.BuiltinTypes.String;
12717 public override void Emit (EmitContext ec)
12719 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12720 if (interpolations == null) {
12721 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12722 if (str != start.Value)
12723 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12730 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12734 var ca = new CallEmitter ();
12735 ca.Emit (ec, best, arguments, loc);
12738 public override void FlowAnalysis (FlowAnalysisContext fc)
12740 if (interpolations != null) {
12741 foreach (var expr in interpolations) {
12742 expr.FlowAnalysis (fc);
12747 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12749 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12750 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12751 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12755 public class InterpolatedStringInsert : CompositeExpression
12757 public InterpolatedStringInsert (Expression expr)
12762 public Expression Alignment { get; set; }
12763 public string Format { get; set; }
12765 protected override void CloneTo (CloneContext clonectx, Expression t)
12767 var target = (InterpolatedStringInsert)t;
12768 target.expr = expr.Clone (clonectx);
12769 if (Alignment != null)
12770 target.Alignment = Alignment.Clone (clonectx);
12773 protected override Expression DoResolve (ResolveContext rc)
12775 var expr = base.DoResolve (rc);
12780 // For better error reporting, assumes the built-in implementation uses object
12783 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12786 public override void FlowAnalysis (FlowAnalysisContext fc)
12788 Child.FlowAnalysis (fc);
12791 public int? ResolveAligment (ResolveContext rc)
12793 var c = Alignment.ResolveLabelConstant (rc);
12797 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12801 var value = (int) c.GetValueAsLong ();
12802 if (value > 32767 || value < -32767) {
12803 rc.Report.Warning (8094, 1, Alignment.Location,
12804 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12811 class ThrowExpression : ExpressionStatement
12815 public ThrowExpression (Expression expr, Location loc)
12821 protected override void CloneTo (CloneContext clonectx, Expression t)
12823 var target = (ThrowExpression)t;
12824 target.expr = expr.Clone (clonectx);
12827 public override bool ContainsEmitWithAwait ()
12829 return expr.ContainsEmitWithAwait ();
12832 public override Expression CreateExpressionTree (ResolveContext rc)
12834 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12838 protected override Expression DoResolve (ResolveContext rc)
12840 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12845 expr = Throw.ConvertType (rc, expr);
12847 eclass = ExprClass.Value;
12848 type = InternalType.ThrowExpr;
12852 public override void Emit (EmitContext ec)
12854 EmitStatement (ec);
12857 public override void EmitStatement (EmitContext ec)
12861 ec.Emit (OpCodes.Throw);
12864 public override void FlowAnalysis (FlowAnalysisContext fc)
12866 expr.FlowAnalysis (fc);
12869 public override Reachability MarkReachable (Reachability rc)
12871 return Reachability.CreateUnreachable ();