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;
2424 type = InternalType.ErrorType;
2428 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2429 if (TypeManager.IsGenericParameter (type)) {
2430 ec.Report.Error (413, loc,
2431 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2432 probe_type_expr.GetSignatureForError ());
2434 ec.Report.Error (77, loc,
2435 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2436 type.GetSignatureForError ());
2441 if (expr.IsNull && type.IsNullableType) {
2442 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2445 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2446 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2450 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2452 e = EmptyCast.Create (e, type);
2453 return ReducedExpression.Create (e, this).Resolve (ec);
2456 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2457 if (TypeManager.IsGenericParameter (etype))
2458 expr = new BoxedCast (expr, etype);
2463 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2464 expr = new BoxedCast (expr, etype);
2468 if (etype != InternalType.ErrorType) {
2469 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2470 etype.GetSignatureForError (), type.GetSignatureForError ());
2476 public override object Accept (StructuralVisitor visitor)
2478 return visitor.Visit (this);
2483 // This represents a typecast in the source language.
2485 public class Cast : ShimExpression {
2486 Expression target_type;
2488 public Cast (Expression cast_type, Expression expr, Location loc)
2491 this.target_type = cast_type;
2495 public Expression TargetType {
2496 get { return target_type; }
2499 protected override Expression DoResolve (ResolveContext ec)
2501 expr = expr.Resolve (ec);
2505 type = target_type.ResolveAsType (ec);
2509 if (type.IsStatic) {
2510 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2514 if (type.IsPointer) {
2515 if (ec.CurrentIterator != null) {
2516 UnsafeInsideIteratorError (ec, loc);
2517 } else if (!ec.IsUnsafe) {
2518 UnsafeError (ec, loc);
2522 eclass = ExprClass.Value;
2524 Constant c = expr as Constant;
2526 c = c.Reduce (ec, type);
2531 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2533 return EmptyCast.Create (res, type);
2538 protected override void CloneTo (CloneContext clonectx, Expression t)
2540 Cast target = (Cast) t;
2542 target.target_type = target_type.Clone (clonectx);
2543 target.expr = expr.Clone (clonectx);
2546 public override object Accept (StructuralVisitor visitor)
2548 return visitor.Visit (this);
2552 public class ImplicitCast : ShimExpression
2556 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2559 this.loc = expr.Location;
2561 this.arrayAccess = arrayAccess;
2564 protected override Expression DoResolve (ResolveContext ec)
2566 expr = expr.Resolve (ec);
2571 expr = ConvertExpressionToArrayIndex (ec, expr);
2573 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2579 public class DeclarationExpression : Expression, IMemoryLocation
2581 LocalVariableReference lvr;
2583 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2585 VariableType = variableType;
2586 Variable = variable;
2587 this.loc = variable.Location;
2590 public LocalVariable Variable { get; set; }
2591 public Expression Initializer { get; set; }
2592 public FullNamedExpression VariableType { get; set; }
2594 public void AddressOf (EmitContext ec, AddressOp mode)
2596 Variable.CreateBuilder (ec);
2598 if (Initializer != null) {
2599 lvr.EmitAssign (ec, Initializer, false, false);
2602 lvr.AddressOf (ec, mode);
2605 protected override void CloneTo (CloneContext clonectx, Expression t)
2607 var target = (DeclarationExpression) t;
2609 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2611 if (Initializer != null)
2612 target.Initializer = Initializer.Clone (clonectx);
2615 public override Expression CreateExpressionTree (ResolveContext rc)
2617 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2621 bool DoResolveCommon (ResolveContext rc)
2623 CheckExpressionVariable (rc);
2625 var var_expr = VariableType as VarExpr;
2626 if (var_expr != null) {
2627 type = InternalType.VarOutType;
2629 type = VariableType.ResolveAsType (rc);
2634 if (Initializer != null) {
2635 Initializer = Initializer.Resolve (rc);
2637 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2638 type = var_expr.Type;
2642 Variable.Type = type;
2643 lvr = new LocalVariableReference (Variable, loc);
2645 eclass = ExprClass.Variable;
2649 protected override Expression DoResolve (ResolveContext rc)
2651 if (DoResolveCommon (rc))
2657 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2659 if (lvr == null && DoResolveCommon (rc))
2660 lvr.ResolveLValue (rc, right_side);
2665 public override void Emit (EmitContext ec)
2667 throw new NotImplementedException ();
2672 // C# 2.0 Default value expression
2674 public class DefaultValueExpression : Expression
2678 public DefaultValueExpression (Expression expr, Location loc)
2684 public Expression Expr {
2690 public override bool IsSideEffectFree {
2696 public override bool ContainsEmitWithAwait ()
2701 public override Expression CreateExpressionTree (ResolveContext ec)
2703 Arguments args = new Arguments (2);
2704 args.Add (new Argument (this));
2705 args.Add (new Argument (new TypeOf (type, loc)));
2706 return CreateExpressionFactoryCall (ec, "Constant", args);
2709 protected override Expression DoResolve (ResolveContext ec)
2711 type = expr.ResolveAsType (ec);
2715 if (type.IsStatic) {
2716 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2720 return new NullLiteral (Location).ConvertImplicitly (type);
2722 if (TypeSpec.IsReferenceType (type))
2723 return new NullConstant (type, loc);
2725 Constant c = New.Constantify (type, expr.Location);
2729 eclass = ExprClass.Variable;
2733 public override void Emit (EmitContext ec)
2735 LocalTemporary temp_storage = new LocalTemporary(type);
2737 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2738 ec.Emit(OpCodes.Initobj, type);
2739 temp_storage.Emit(ec);
2740 temp_storage.Release (ec);
2744 public override SLE.Expression MakeExpression (BuilderContext ctx)
2746 return SLE.Expression.Default (type.GetMetaInfo ());
2750 protected override void CloneTo (CloneContext clonectx, Expression t)
2752 DefaultValueExpression target = (DefaultValueExpression) t;
2754 target.expr = expr.Clone (clonectx);
2757 public override object Accept (StructuralVisitor visitor)
2759 return visitor.Visit (this);
2764 /// Binary operators
2766 public class Binary : Expression, IDynamicBinder
2768 public class PredefinedOperator
2770 protected readonly TypeSpec left;
2771 protected readonly TypeSpec right;
2772 protected readonly TypeSpec left_unwrap;
2773 protected readonly TypeSpec right_unwrap;
2774 public readonly Operator OperatorsMask;
2775 public TypeSpec ReturnType;
2777 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2778 : this (ltype, rtype, op_mask, ltype)
2782 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2783 : this (type, type, op_mask, return_type)
2787 public PredefinedOperator (TypeSpec type, Operator op_mask)
2788 : this (type, type, op_mask, type)
2792 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2794 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2795 throw new InternalErrorException ("Only masked values can be used");
2797 if ((op_mask & Operator.NullableMask) != 0) {
2798 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2799 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2801 left_unwrap = ltype;
2802 right_unwrap = rtype;
2807 this.OperatorsMask = op_mask;
2808 this.ReturnType = return_type;
2811 public bool IsLifted {
2813 return (OperatorsMask & Operator.NullableMask) != 0;
2817 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2821 var left_expr = b.left;
2822 var right_expr = b.right;
2824 b.type = ReturnType;
2827 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2828 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2829 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2832 if (right_expr.IsNull) {
2833 if ((b.oper & Operator.EqualityMask) != 0) {
2834 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2835 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2836 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2837 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2838 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2840 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2841 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2843 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2844 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2846 return b.CreateLiftedValueTypeResult (rc, left);
2848 } else if (left_expr.IsNull) {
2849 if ((b.oper & Operator.EqualityMask) != 0) {
2850 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2851 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2852 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2853 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2854 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2856 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2857 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2859 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2860 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2862 return b.CreateLiftedValueTypeResult (rc, right);
2868 // A user operators does not support multiple user conversions, but decimal type
2869 // is considered to be predefined type therefore we apply predefined operators rules
2870 // and then look for decimal user-operator implementation
2872 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2873 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2874 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2876 return b.ResolveUserOperator (rc, b.left, b.right);
2879 c = right_expr as Constant;
2881 if (c.IsDefaultValue) {
2885 // (expr + 0) to expr
2886 // (expr - 0) to expr
2887 // (bool? | false) to bool?
2889 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2890 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2891 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2892 return ReducedExpression.Create (b.left, b).Resolve (rc);
2896 // Optimizes (value &/&& 0) to 0
2898 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2899 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2900 return ReducedExpression.Create (side_effect, b);
2904 // Optimizes (bool? & true) to bool?
2906 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2907 return ReducedExpression.Create (b.left, b).Resolve (rc);
2911 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2912 return ReducedExpression.Create (b.left, b).Resolve (rc);
2914 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2915 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2919 c = b.left as Constant;
2921 if (c.IsDefaultValue) {
2925 // (0 + expr) to expr
2926 // (false | bool?) to bool?
2928 if (b.oper == Operator.Addition ||
2929 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2930 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2931 return ReducedExpression.Create (b.right, b).Resolve (rc);
2935 // Optimizes (false && expr) to false
2937 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2938 // No rhs side-effects
2939 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2940 return ReducedExpression.Create (c, b);
2944 // Optimizes (0 & value) to 0
2946 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2947 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2948 return ReducedExpression.Create (side_effect, b);
2952 // Optimizes (true & bool?) to bool?
2954 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2955 return ReducedExpression.Create (b.right, b).Resolve (rc);
2959 // Optimizes (true || expr) to true
2961 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2962 // No rhs side-effects
2963 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2964 return ReducedExpression.Create (c, b);
2968 if (b.oper == Operator.Multiply && c.IsOneInteger)
2969 return ReducedExpression.Create (b.right, b).Resolve (rc);
2973 var lifted = new Nullable.LiftedBinaryOperator (b);
2975 TypeSpec ltype, rtype;
2976 if (b.left.Type.IsNullableType) {
2977 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2978 ltype = left_unwrap;
2983 if (b.right.Type.IsNullableType) {
2984 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2985 rtype = right_unwrap;
2990 lifted.Left = b.left.IsNull ?
2991 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2992 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2994 lifted.Right = b.right.IsNull ?
2995 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2996 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2998 return lifted.Resolve (rc);
3001 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3002 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3007 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3010 // We are dealing with primitive types only
3012 return left == ltype && ltype == rtype;
3015 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3018 if (left == lexpr.Type && right == rexpr.Type)
3021 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3022 Convert.ImplicitConversionExists (ec, rexpr, right);
3025 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3027 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3028 return best_operator;
3030 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3034 if (left != null && best_operator.left != null) {
3035 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3039 // When second argument is same as the first one, the result is same
3041 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3042 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3045 if (result == 0 || result > 2)
3048 return result == 1 ? best_operator : this;
3052 sealed class PredefinedStringOperator : PredefinedOperator
3054 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3055 : base (type, type, op_mask, retType)
3059 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3060 : base (ltype, rtype, op_mask, retType)
3064 public override Expression ConvertResult (ResolveContext ec, Binary b)
3067 // Use original expression for nullable arguments
3069 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3071 b.left = unwrap.Original;
3073 unwrap = b.right as Nullable.Unwrap;
3075 b.right = unwrap.Original;
3077 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3078 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3081 // Start a new concat expression using converted expression
3083 return StringConcat.Create (ec, b.left, b.right, b.loc);
3087 sealed class PredefinedEqualityOperator : PredefinedOperator
3089 MethodSpec equal_method, inequal_method;
3091 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3092 : base (arg, arg, Operator.EqualityMask, retType)
3096 public override Expression ConvertResult (ResolveContext ec, Binary b)
3098 b.type = ReturnType;
3100 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3101 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3103 Arguments args = new Arguments (2);
3104 args.Add (new Argument (b.left));
3105 args.Add (new Argument (b.right));
3108 if (b.oper == Operator.Equality) {
3109 if (equal_method == null) {
3110 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3111 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3112 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3113 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3115 throw new NotImplementedException (left.GetSignatureForError ());
3118 method = equal_method;
3120 if (inequal_method == null) {
3121 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3122 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3123 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3124 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3126 throw new NotImplementedException (left.GetSignatureForError ());
3129 method = inequal_method;
3132 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3136 class PredefinedPointerOperator : PredefinedOperator
3138 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3139 : base (ltype, rtype, op_mask)
3143 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3144 : base (ltype, rtype, op_mask, retType)
3148 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3149 : base (type, op_mask, return_type)
3153 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3156 if (!lexpr.Type.IsPointer)
3159 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3163 if (right == null) {
3164 if (!rexpr.Type.IsPointer)
3167 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3174 public override Expression ConvertResult (ResolveContext ec, Binary b)
3177 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3178 } else if (right != null) {
3179 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3182 TypeSpec r_type = ReturnType;
3183 Expression left_arg, right_arg;
3184 if (r_type == null) {
3187 right_arg = b.right;
3188 r_type = b.left.Type;
3192 r_type = b.right.Type;
3196 right_arg = b.right;
3199 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3204 public enum Operator {
3205 Multiply = 0 | ArithmeticMask,
3206 Division = 1 | ArithmeticMask,
3207 Modulus = 2 | ArithmeticMask,
3208 Addition = 3 | ArithmeticMask | AdditionMask,
3209 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3211 LeftShift = 5 | ShiftMask,
3212 RightShift = 6 | ShiftMask,
3214 LessThan = 7 | ComparisonMask | RelationalMask,
3215 GreaterThan = 8 | ComparisonMask | RelationalMask,
3216 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3217 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3218 Equality = 11 | ComparisonMask | EqualityMask,
3219 Inequality = 12 | ComparisonMask | EqualityMask,
3221 BitwiseAnd = 13 | BitwiseMask,
3222 ExclusiveOr = 14 | BitwiseMask,
3223 BitwiseOr = 15 | BitwiseMask,
3225 LogicalAnd = 16 | LogicalMask,
3226 LogicalOr = 17 | LogicalMask,
3231 ValuesOnlyMask = ArithmeticMask - 1,
3232 ArithmeticMask = 1 << 5,
3234 ComparisonMask = 1 << 7,
3235 EqualityMask = 1 << 8,
3236 BitwiseMask = 1 << 9,
3237 LogicalMask = 1 << 10,
3238 AdditionMask = 1 << 11,
3239 SubtractionMask = 1 << 12,
3240 RelationalMask = 1 << 13,
3242 DecomposedMask = 1 << 19,
3243 NullableMask = 1 << 20
3247 public enum State : byte
3251 UserOperatorsExcluded = 1 << 2
3254 readonly Operator oper;
3255 Expression left, right;
3257 ConvCast.Mode enum_conversion;
3259 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3260 : this (oper, left, right, State.Compound)
3264 public Binary (Operator oper, Expression left, Expression right, State state)
3265 : this (oper, left, right)
3270 public Binary (Operator oper, Expression left, Expression right)
3271 : this (oper, left, right, left.Location)
3275 public Binary (Operator oper, Expression left, Expression right, Location loc)
3285 public bool IsCompound {
3287 return (state & State.Compound) != 0;
3291 public Operator Oper {
3297 public Expression Left {
3303 public Expression Right {
3309 public override Location StartLocation {
3311 return left.StartLocation;
3318 /// Returns a stringified representation of the Operator
3320 string OperName (Operator oper)
3324 case Operator.Multiply:
3327 case Operator.Division:
3330 case Operator.Modulus:
3333 case Operator.Addition:
3336 case Operator.Subtraction:
3339 case Operator.LeftShift:
3342 case Operator.RightShift:
3345 case Operator.LessThan:
3348 case Operator.GreaterThan:
3351 case Operator.LessThanOrEqual:
3354 case Operator.GreaterThanOrEqual:
3357 case Operator.Equality:
3360 case Operator.Inequality:
3363 case Operator.BitwiseAnd:
3366 case Operator.BitwiseOr:
3369 case Operator.ExclusiveOr:
3372 case Operator.LogicalOr:
3375 case Operator.LogicalAnd:
3379 s = oper.ToString ();
3389 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3391 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3394 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3396 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3400 l = left.Type.GetSignatureForError ();
3401 r = right.Type.GetSignatureForError ();
3403 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3407 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3409 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3412 public override void FlowAnalysis (FlowAnalysisContext fc)
3415 // Optimized version when on-true/on-false data are not needed
3417 if ((oper & Operator.LogicalMask) == 0) {
3418 left.FlowAnalysis (fc);
3419 right.FlowAnalysis (fc);
3423 left.FlowAnalysisConditional (fc);
3424 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3425 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3427 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3428 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3429 right.FlowAnalysisConditional (fc);
3431 if (oper == Operator.LogicalOr)
3432 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3434 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3437 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3439 if ((oper & Operator.LogicalMask) == 0) {
3440 base.FlowAnalysisConditional (fc);
3444 left.FlowAnalysisConditional (fc);
3445 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3446 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3448 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3449 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3450 right.FlowAnalysisConditional (fc);
3452 var lc = left as Constant;
3453 if (oper == Operator.LogicalOr) {
3454 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3455 if (lc != null && lc.IsDefaultValue)
3456 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3458 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3460 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3461 if (lc != null && !lc.IsDefaultValue)
3462 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3464 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3469 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3471 string GetOperatorExpressionTypeName ()
3474 case Operator.Addition:
3475 return IsCompound ? "AddAssign" : "Add";
3476 case Operator.BitwiseAnd:
3477 return IsCompound ? "AndAssign" : "And";
3478 case Operator.BitwiseOr:
3479 return IsCompound ? "OrAssign" : "Or";
3480 case Operator.Division:
3481 return IsCompound ? "DivideAssign" : "Divide";
3482 case Operator.ExclusiveOr:
3483 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3484 case Operator.Equality:
3486 case Operator.GreaterThan:
3487 return "GreaterThan";
3488 case Operator.GreaterThanOrEqual:
3489 return "GreaterThanOrEqual";
3490 case Operator.Inequality:
3492 case Operator.LeftShift:
3493 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3494 case Operator.LessThan:
3496 case Operator.LessThanOrEqual:
3497 return "LessThanOrEqual";
3498 case Operator.LogicalAnd:
3500 case Operator.LogicalOr:
3502 case Operator.Modulus:
3503 return IsCompound ? "ModuloAssign" : "Modulo";
3504 case Operator.Multiply:
3505 return IsCompound ? "MultiplyAssign" : "Multiply";
3506 case Operator.RightShift:
3507 return IsCompound ? "RightShiftAssign" : "RightShift";
3508 case Operator.Subtraction:
3509 return IsCompound ? "SubtractAssign" : "Subtract";
3511 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3515 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3518 case Operator.Addition:
3519 return CSharp.Operator.OpType.Addition;
3520 case Operator.BitwiseAnd:
3521 case Operator.LogicalAnd:
3522 return CSharp.Operator.OpType.BitwiseAnd;
3523 case Operator.BitwiseOr:
3524 case Operator.LogicalOr:
3525 return CSharp.Operator.OpType.BitwiseOr;
3526 case Operator.Division:
3527 return CSharp.Operator.OpType.Division;
3528 case Operator.Equality:
3529 return CSharp.Operator.OpType.Equality;
3530 case Operator.ExclusiveOr:
3531 return CSharp.Operator.OpType.ExclusiveOr;
3532 case Operator.GreaterThan:
3533 return CSharp.Operator.OpType.GreaterThan;
3534 case Operator.GreaterThanOrEqual:
3535 return CSharp.Operator.OpType.GreaterThanOrEqual;
3536 case Operator.Inequality:
3537 return CSharp.Operator.OpType.Inequality;
3538 case Operator.LeftShift:
3539 return CSharp.Operator.OpType.LeftShift;
3540 case Operator.LessThan:
3541 return CSharp.Operator.OpType.LessThan;
3542 case Operator.LessThanOrEqual:
3543 return CSharp.Operator.OpType.LessThanOrEqual;
3544 case Operator.Modulus:
3545 return CSharp.Operator.OpType.Modulus;
3546 case Operator.Multiply:
3547 return CSharp.Operator.OpType.Multiply;
3548 case Operator.RightShift:
3549 return CSharp.Operator.OpType.RightShift;
3550 case Operator.Subtraction:
3551 return CSharp.Operator.OpType.Subtraction;
3553 throw new InternalErrorException (op.ToString ());
3557 public override bool ContainsEmitWithAwait ()
3559 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3562 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3567 case Operator.Multiply:
3568 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3569 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3570 opcode = OpCodes.Mul_Ovf;
3571 else if (!IsFloat (l))
3572 opcode = OpCodes.Mul_Ovf_Un;
3574 opcode = OpCodes.Mul;
3576 opcode = OpCodes.Mul;
3580 case Operator.Division:
3582 opcode = OpCodes.Div_Un;
3584 opcode = OpCodes.Div;
3587 case Operator.Modulus:
3589 opcode = OpCodes.Rem_Un;
3591 opcode = OpCodes.Rem;
3594 case Operator.Addition:
3595 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3596 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3597 opcode = OpCodes.Add_Ovf;
3598 else if (!IsFloat (l))
3599 opcode = OpCodes.Add_Ovf_Un;
3601 opcode = OpCodes.Add;
3603 opcode = OpCodes.Add;
3606 case Operator.Subtraction:
3607 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3608 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3609 opcode = OpCodes.Sub_Ovf;
3610 else if (!IsFloat (l))
3611 opcode = OpCodes.Sub_Ovf_Un;
3613 opcode = OpCodes.Sub;
3615 opcode = OpCodes.Sub;
3618 case Operator.RightShift:
3619 if (!(right is IntConstant)) {
3620 ec.EmitInt (GetShiftMask (l));
3621 ec.Emit (OpCodes.And);
3625 opcode = OpCodes.Shr_Un;
3627 opcode = OpCodes.Shr;
3630 case Operator.LeftShift:
3631 if (!(right is IntConstant)) {
3632 ec.EmitInt (GetShiftMask (l));
3633 ec.Emit (OpCodes.And);
3636 opcode = OpCodes.Shl;
3639 case Operator.Equality:
3640 opcode = OpCodes.Ceq;
3643 case Operator.Inequality:
3644 ec.Emit (OpCodes.Ceq);
3647 opcode = OpCodes.Ceq;
3650 case Operator.LessThan:
3652 opcode = OpCodes.Clt_Un;
3654 opcode = OpCodes.Clt;
3657 case Operator.GreaterThan:
3659 opcode = OpCodes.Cgt_Un;
3661 opcode = OpCodes.Cgt;
3664 case Operator.LessThanOrEqual:
3665 if (IsUnsigned (l) || IsFloat (l))
3666 ec.Emit (OpCodes.Cgt_Un);
3668 ec.Emit (OpCodes.Cgt);
3671 opcode = OpCodes.Ceq;
3674 case Operator.GreaterThanOrEqual:
3675 if (IsUnsigned (l) || IsFloat (l))
3676 ec.Emit (OpCodes.Clt_Un);
3678 ec.Emit (OpCodes.Clt);
3682 opcode = OpCodes.Ceq;
3685 case Operator.BitwiseOr:
3686 opcode = OpCodes.Or;
3689 case Operator.BitwiseAnd:
3690 opcode = OpCodes.And;
3693 case Operator.ExclusiveOr:
3694 opcode = OpCodes.Xor;
3698 throw new InternalErrorException (oper.ToString ());
3704 static int GetShiftMask (TypeSpec type)
3706 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3709 static bool IsUnsigned (TypeSpec t)
3711 switch (t.BuiltinType) {
3712 case BuiltinTypeSpec.Type.Char:
3713 case BuiltinTypeSpec.Type.UInt:
3714 case BuiltinTypeSpec.Type.ULong:
3715 case BuiltinTypeSpec.Type.UShort:
3716 case BuiltinTypeSpec.Type.Byte:
3723 static bool IsFloat (TypeSpec t)
3725 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3728 public Expression ResolveOperator (ResolveContext rc)
3730 eclass = ExprClass.Value;
3732 TypeSpec l = left.Type;
3733 TypeSpec r = right.Type;
3735 bool primitives_only = false;
3738 // Handles predefined primitive types
3740 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3741 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3742 if ((oper & Operator.ShiftMask) == 0) {
3743 if (!DoBinaryOperatorPromotion (rc))
3746 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3750 if (l.IsPointer || r.IsPointer)
3751 return ResolveOperatorPointer (rc, l, r);
3754 if ((state & State.UserOperatorsExcluded) == 0) {
3755 expr = ResolveUserOperator (rc, left, right);
3760 bool lenum = l.IsEnum;
3761 bool renum = r.IsEnum;
3762 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3766 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3767 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3772 if ((oper & Operator.BitwiseMask) != 0) {
3773 expr = EmptyCast.Create (expr, type);
3774 enum_conversion = GetEnumResultCast (type);
3776 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3777 expr = OptimizeAndOperation (expr);
3781 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3782 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3785 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3786 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3790 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3793 // We cannot break here there is also Enum + String possible match
3794 // which is not ambiguous with predefined enum operators
3797 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3798 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3802 } else if (l.IsDelegate || r.IsDelegate) {
3806 expr = ResolveOperatorDelegate (rc, l, r);
3808 // TODO: Can this be ambiguous
3816 // Equality operators are more complicated
3818 if ((oper & Operator.EqualityMask) != 0) {
3819 return ResolveEquality (rc, l, r, primitives_only);
3822 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3826 if (primitives_only)
3830 // Lifted operators have lower priority
3832 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3835 static bool IsEnumOrNullableEnum (TypeSpec type)
3837 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3841 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3842 // if 'left' is not an enumeration constant, create one from the type of 'right'
3843 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3846 case Operator.BitwiseOr:
3847 case Operator.BitwiseAnd:
3848 case Operator.ExclusiveOr:
3849 case Operator.Equality:
3850 case Operator.Inequality:
3851 case Operator.LessThan:
3852 case Operator.LessThanOrEqual:
3853 case Operator.GreaterThan:
3854 case Operator.GreaterThanOrEqual:
3855 if (left.Type.IsEnum)
3858 if (left.IsZeroInteger)
3859 return left.Reduce (ec, right.Type);
3863 case Operator.Addition:
3864 case Operator.Subtraction:
3867 case Operator.Multiply:
3868 case Operator.Division:
3869 case Operator.Modulus:
3870 case Operator.LeftShift:
3871 case Operator.RightShift:
3872 if (right.Type.IsEnum || left.Type.IsEnum)
3881 // The `|' operator used on types which were extended is dangerous
3883 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3885 OpcodeCast lcast = left as OpcodeCast;
3886 if (lcast != null) {
3887 if (IsUnsigned (lcast.UnderlyingType))
3891 OpcodeCast rcast = right as OpcodeCast;
3892 if (rcast != null) {
3893 if (IsUnsigned (rcast.UnderlyingType))
3897 if (lcast == null && rcast == null)
3900 // FIXME: consider constants
3902 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3903 ec.Report.Warning (675, 3, loc,
3904 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3905 ltype.GetSignatureForError ());
3908 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3910 return new PredefinedOperator[] {
3912 // Pointer arithmetic:
3914 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3915 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3916 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3917 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3919 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3920 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3921 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3922 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3925 // T* operator + (int y, T* x);
3926 // T* operator + (uint y, T *x);
3927 // T* operator + (long y, T *x);
3928 // T* operator + (ulong y, T *x);
3930 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3931 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3932 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3933 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3936 // long operator - (T* x, T *y)
3938 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3942 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3944 TypeSpec bool_type = types.Bool;
3947 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3948 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3949 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3950 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3951 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3952 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3953 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3955 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3956 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3957 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3958 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3959 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3960 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3961 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3963 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3964 // Remaining string operators are in lifted tables
3966 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3968 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3969 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3970 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3974 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3976 var types = module.Compiler.BuiltinTypes;
3979 // Not strictly lifted but need to be in second group otherwise expressions like
3980 // int + null would resolve to +(object, string) instead of +(int?, int?)
3982 var string_operators = new [] {
3983 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3984 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3987 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3988 if (nullable == null)
3989 return string_operators;
3991 var bool_type = types.Bool;
3993 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3994 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3995 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3996 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3997 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3998 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3999 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4000 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4003 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4004 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4005 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4006 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4007 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4008 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4009 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4011 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4012 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4013 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4014 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4015 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4016 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4017 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4019 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4021 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4022 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4023 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4025 string_operators [0],
4026 string_operators [1]
4030 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4032 TypeSpec bool_type = types.Bool;
4035 new PredefinedEqualityOperator (types.String, bool_type),
4036 new PredefinedEqualityOperator (types.Delegate, bool_type),
4037 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4038 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4039 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4040 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4041 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4042 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4043 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4044 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4048 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4050 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4052 if (nullable == null)
4053 return new PredefinedOperator [0];
4055 var types = module.Compiler.BuiltinTypes;
4056 var bool_type = types.Bool;
4057 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4058 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4059 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4060 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4061 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4062 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4063 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4064 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4067 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4068 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4069 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4070 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4071 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4072 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4073 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4074 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4079 // 7.2.6.2 Binary numeric promotions
4081 bool DoBinaryOperatorPromotion (ResolveContext rc)
4083 TypeSpec ltype = left.Type;
4084 if (ltype.IsNullableType) {
4085 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4089 // This is numeric promotion code only
4091 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4094 TypeSpec rtype = right.Type;
4095 if (rtype.IsNullableType) {
4096 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4099 var lb = ltype.BuiltinType;
4100 var rb = rtype.BuiltinType;
4104 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4105 type = rc.BuiltinTypes.Decimal;
4106 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4107 type = rc.BuiltinTypes.Double;
4108 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4109 type = rc.BuiltinTypes.Float;
4110 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4111 type = rc.BuiltinTypes.ULong;
4113 if (IsSignedType (lb)) {
4114 expr = ConvertSignedConstant (left, type);
4118 } else if (IsSignedType (rb)) {
4119 expr = ConvertSignedConstant (right, type);
4125 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4126 type = rc.BuiltinTypes.Long;
4127 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4128 type = rc.BuiltinTypes.UInt;
4130 if (IsSignedType (lb)) {
4131 expr = ConvertSignedConstant (left, type);
4133 type = rc.BuiltinTypes.Long;
4134 } else if (IsSignedType (rb)) {
4135 expr = ConvertSignedConstant (right, type);
4137 type = rc.BuiltinTypes.Long;
4140 type = rc.BuiltinTypes.Int;
4143 if (ltype != type) {
4144 expr = PromoteExpression (rc, left, type);
4151 if (rtype != type) {
4152 expr = PromoteExpression (rc, right, type);
4162 static bool IsSignedType (BuiltinTypeSpec.Type type)
4165 case BuiltinTypeSpec.Type.Int:
4166 case BuiltinTypeSpec.Type.Short:
4167 case BuiltinTypeSpec.Type.SByte:
4168 case BuiltinTypeSpec.Type.Long:
4175 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4177 var c = expr as Constant;
4181 return c.ConvertImplicitly (type);
4184 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4186 if (expr.Type.IsNullableType) {
4187 return Convert.ImplicitConversionStandard (rc, expr,
4188 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4191 var c = expr as Constant;
4193 return c.ConvertImplicitly (type);
4195 return Convert.ImplicitNumericConversion (expr, type);
4198 protected override Expression DoResolve (ResolveContext ec)
4203 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4204 left = ((ParenthesizedExpression) left).Expr;
4205 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4209 if (left.eclass == ExprClass.Type) {
4210 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4214 left = left.Resolve (ec);
4219 right = right.Resolve (ec);
4223 Constant lc = left as Constant;
4224 Constant rc = right as Constant;
4226 // The conversion rules are ignored in enum context but why
4227 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4228 lc = EnumLiftUp (ec, lc, rc);
4230 rc = EnumLiftUp (ec, rc, lc);
4233 if (rc != null && lc != null) {
4234 int prev_e = ec.Report.Errors;
4235 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4236 if (e != null || ec.Report.Errors != prev_e)
4240 // Comparison warnings
4241 if ((oper & Operator.ComparisonMask) != 0) {
4242 if (left.Equals (right)) {
4243 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4245 CheckOutOfRangeComparison (ec, lc, right.Type);
4246 CheckOutOfRangeComparison (ec, rc, left.Type);
4249 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4250 return DoResolveDynamic (ec);
4252 return DoResolveCore (ec, left, right);
4255 Expression DoResolveDynamic (ResolveContext rc)
4258 var rt = right.Type;
4259 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4260 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4261 Error_OperatorCannotBeApplied (rc, left, right);
4268 // Special handling for logical boolean operators which require rhs not to be
4269 // evaluated based on lhs value
4271 if ((oper & Operator.LogicalMask) != 0) {
4272 Expression cond_left, cond_right, expr;
4274 args = new Arguments (2);
4276 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4277 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4279 var cond_args = new Arguments (1);
4280 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4283 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4284 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4286 left = temp.CreateReferenceExpression (rc, loc);
4287 if (oper == Operator.LogicalAnd) {
4288 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4291 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4295 args.Add (new Argument (left));
4296 args.Add (new Argument (right));
4297 cond_right = new DynamicExpressionStatement (this, args, loc);
4299 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4301 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4302 rc.Report.Error (7083, left.Location,
4303 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4304 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4308 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4309 args.Add (new Argument (right));
4310 right = new DynamicExpressionStatement (this, args, loc);
4313 // bool && dynamic => (temp = left) ? temp && right : temp;
4314 // bool || dynamic => (temp = left) ? temp : temp || right;
4316 if (oper == Operator.LogicalAnd) {
4318 cond_right = temp.CreateReferenceExpression (rc, loc);
4320 cond_left = temp.CreateReferenceExpression (rc, loc);
4324 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4327 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4330 args = new Arguments (2);
4331 args.Add (new Argument (left));
4332 args.Add (new Argument (right));
4333 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4336 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4338 Expression expr = ResolveOperator (ec);
4340 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4342 if (left == null || right == null)
4343 throw new InternalErrorException ("Invalid conversion");
4345 if (oper == Operator.BitwiseOr)
4346 CheckBitwiseOrOnSignExtended (ec);
4351 public override SLE.Expression MakeExpression (BuilderContext ctx)
4353 return MakeExpression (ctx, left, right);
4356 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4358 var le = left.MakeExpression (ctx);
4359 var re = right.MakeExpression (ctx);
4360 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4363 case Operator.Addition:
4364 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4365 case Operator.BitwiseAnd:
4366 return SLE.Expression.And (le, re);
4367 case Operator.BitwiseOr:
4368 return SLE.Expression.Or (le, re);
4369 case Operator.Division:
4370 return SLE.Expression.Divide (le, re);
4371 case Operator.Equality:
4372 return SLE.Expression.Equal (le, re);
4373 case Operator.ExclusiveOr:
4374 return SLE.Expression.ExclusiveOr (le, re);
4375 case Operator.GreaterThan:
4376 return SLE.Expression.GreaterThan (le, re);
4377 case Operator.GreaterThanOrEqual:
4378 return SLE.Expression.GreaterThanOrEqual (le, re);
4379 case Operator.Inequality:
4380 return SLE.Expression.NotEqual (le, re);
4381 case Operator.LeftShift:
4382 return SLE.Expression.LeftShift (le, re);
4383 case Operator.LessThan:
4384 return SLE.Expression.LessThan (le, re);
4385 case Operator.LessThanOrEqual:
4386 return SLE.Expression.LessThanOrEqual (le, re);
4387 case Operator.LogicalAnd:
4388 return SLE.Expression.AndAlso (le, re);
4389 case Operator.LogicalOr:
4390 return SLE.Expression.OrElse (le, re);
4391 case Operator.Modulus:
4392 return SLE.Expression.Modulo (le, re);
4393 case Operator.Multiply:
4394 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4395 case Operator.RightShift:
4396 return SLE.Expression.RightShift (le, re);
4397 case Operator.Subtraction:
4398 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4400 throw new NotImplementedException (oper.ToString ());
4405 // D operator + (D x, D y)
4406 // D operator - (D x, D y)
4408 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4410 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4412 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4413 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4418 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4419 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4429 MethodSpec method = null;
4430 Arguments args = new Arguments (2);
4431 args.Add (new Argument (left));
4432 args.Add (new Argument (right));
4434 if (oper == Operator.Addition) {
4435 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4436 } else if (oper == Operator.Subtraction) {
4437 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4441 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4443 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4444 return new ClassCast (expr, l);
4448 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4450 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4453 // bool operator == (E x, E y);
4454 // bool operator != (E x, E y);
4455 // bool operator < (E x, E y);
4456 // bool operator > (E x, E y);
4457 // bool operator <= (E x, E y);
4458 // bool operator >= (E x, E y);
4460 // E operator & (E x, E y);
4461 // E operator | (E x, E y);
4462 // E operator ^ (E x, E y);
4465 if ((oper & Operator.ComparisonMask) != 0) {
4466 type = rc.BuiltinTypes.Bool;
4472 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4478 if (ltype == rtype) {
4482 var lifted = new Nullable.LiftedBinaryOperator (this);
4484 lifted.Right = right;
4485 return lifted.Resolve (rc);
4488 if (renum && !ltype.IsNullableType) {
4489 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4494 } else if (lenum && !rtype.IsNullableType) {
4495 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4503 // Now try lifted version of predefined operator
4505 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4506 if (nullable_type != null) {
4507 if (renum && !ltype.IsNullableType) {
4508 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4510 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4513 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4516 if ((oper & Operator.BitwiseMask) != 0)
4520 if ((oper & Operator.BitwiseMask) != 0)
4521 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4523 return CreateLiftedValueTypeResult (rc, rtype);
4527 var lifted = new Nullable.LiftedBinaryOperator (this);
4529 lifted.Right = right;
4530 return lifted.Resolve (rc);
4532 } else if (lenum && !rtype.IsNullableType) {
4533 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4535 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4538 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4541 if ((oper & Operator.BitwiseMask) != 0)
4545 if ((oper & Operator.BitwiseMask) != 0)
4546 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4548 return CreateLiftedValueTypeResult (rc, ltype);
4552 var lifted = new Nullable.LiftedBinaryOperator (this);
4554 lifted.Right = expr;
4555 return lifted.Resolve (rc);
4557 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4558 Nullable.Unwrap unwrap = null;
4559 if (left.IsNull || right.IsNull) {
4560 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4561 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4563 if ((oper & Operator.RelationalMask) != 0)
4564 return CreateLiftedValueTypeResult (rc, rtype);
4566 if ((oper & Operator.BitwiseMask) != 0)
4567 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4570 return CreateLiftedValueTypeResult (rc, left.Type);
4572 // Equality operators are valid between E? and null
4574 unwrap = new Nullable.Unwrap (right);
4576 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4580 if ((oper & Operator.BitwiseMask) != 0)
4585 var lifted = new Nullable.LiftedBinaryOperator (this);
4587 lifted.Right = right;
4588 lifted.UnwrapRight = unwrap;
4589 return lifted.Resolve (rc);
4591 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4592 Nullable.Unwrap unwrap = null;
4593 if (right.IsNull || left.IsNull) {
4594 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4595 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4597 if ((oper & Operator.RelationalMask) != 0)
4598 return CreateLiftedValueTypeResult (rc, ltype);
4600 if ((oper & Operator.BitwiseMask) != 0)
4601 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4604 return CreateLiftedValueTypeResult (rc, right.Type);
4606 // Equality operators are valid between E? and null
4608 unwrap = new Nullable.Unwrap (left);
4610 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4614 if ((oper & Operator.BitwiseMask) != 0)
4619 var lifted = new Nullable.LiftedBinaryOperator (this);
4621 lifted.UnwrapLeft = unwrap;
4622 lifted.Right = expr;
4623 return lifted.Resolve (rc);
4631 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4633 TypeSpec underlying_type;
4634 if (expr.Type.IsNullableType) {
4635 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4637 underlying_type = EnumSpec.GetUnderlyingType (nt);
4639 underlying_type = nt;
4640 } else if (expr.Type.IsEnum) {
4641 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4643 underlying_type = expr.Type;
4646 switch (underlying_type.BuiltinType) {
4647 case BuiltinTypeSpec.Type.SByte:
4648 case BuiltinTypeSpec.Type.Byte:
4649 case BuiltinTypeSpec.Type.Short:
4650 case BuiltinTypeSpec.Type.UShort:
4651 underlying_type = rc.BuiltinTypes.Int;
4655 if (expr.Type.IsNullableType || liftType)
4656 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4658 if (expr.Type == underlying_type)
4661 return EmptyCast.Create (expr, underlying_type);
4664 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4667 // U operator - (E e, E f)
4668 // E operator - (E e, U x) // Internal decomposition operator
4669 // E operator - (U x, E e) // Internal decomposition operator
4671 // E operator + (E e, U x)
4672 // E operator + (U x, E e)
4681 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4687 if (!enum_type.IsNullableType) {
4688 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4690 if (oper == Operator.Subtraction)
4691 expr = ConvertEnumSubtractionResult (rc, expr);
4693 expr = ConvertEnumAdditionalResult (expr, enum_type);
4695 enum_conversion = GetEnumResultCast (expr.Type);
4700 var nullable = rc.Module.PredefinedTypes.Nullable;
4703 // Don't try nullable version when nullable type is undefined
4705 if (!nullable.IsDefined)
4708 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4711 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4713 if (oper == Operator.Subtraction)
4714 expr = ConvertEnumSubtractionResult (rc, expr);
4716 expr = ConvertEnumAdditionalResult (expr, enum_type);
4718 enum_conversion = GetEnumResultCast (expr.Type);
4724 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4726 return EmptyCast.Create (expr, enumType);
4729 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4732 // Enumeration subtraction has different result type based on
4735 TypeSpec result_type;
4736 if (left.Type == right.Type) {
4737 var c = right as EnumConstant;
4738 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4740 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4741 // E which is not what expressions E - 1 or 0 - E return
4743 result_type = left.Type;
4745 result_type = left.Type.IsNullableType ?
4746 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4747 EnumSpec.GetUnderlyingType (left.Type);
4750 if (IsEnumOrNullableEnum (left.Type)) {
4751 result_type = left.Type;
4753 result_type = right.Type;
4756 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4757 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4760 return EmptyCast.Create (expr, result_type);
4763 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4765 if (type.IsNullableType)
4766 type = Nullable.NullableInfo.GetUnderlyingType (type);
4769 type = EnumSpec.GetUnderlyingType (type);
4771 switch (type.BuiltinType) {
4772 case BuiltinTypeSpec.Type.SByte:
4773 return ConvCast.Mode.I4_I1;
4774 case BuiltinTypeSpec.Type.Byte:
4775 return ConvCast.Mode.I4_U1;
4776 case BuiltinTypeSpec.Type.Short:
4777 return ConvCast.Mode.I4_I2;
4778 case BuiltinTypeSpec.Type.UShort:
4779 return ConvCast.Mode.I4_U2;
4786 // Equality operators rules
4788 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4791 type = ec.BuiltinTypes.Bool;
4792 bool no_arg_conv = false;
4794 if (!primitives_only) {
4797 // a, Both operands are reference-type values or the value null
4798 // b, One operand is a value of type T where T is a type-parameter and
4799 // the other operand is the value null. Furthermore T does not have the
4800 // value type constraint
4802 // LAMESPEC: Very confusing details in the specification, basically any
4803 // reference like type-parameter is allowed
4805 var tparam_l = l as TypeParameterSpec;
4806 var tparam_r = r as TypeParameterSpec;
4807 if (tparam_l != null) {
4808 if (right is NullLiteral) {
4809 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4812 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4816 if (!tparam_l.IsReferenceType)
4819 l = tparam_l.GetEffectiveBase ();
4820 left = new BoxedCast (left, l);
4821 } else if (left is NullLiteral && tparam_r == null) {
4822 if (TypeSpec.IsReferenceType (r))
4825 if (r.Kind == MemberKind.InternalCompilerType)
4829 if (tparam_r != null) {
4830 if (left is NullLiteral) {
4831 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4834 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4838 if (!tparam_r.IsReferenceType)
4841 r = tparam_r.GetEffectiveBase ();
4842 right = new BoxedCast (right, r);
4843 } else if (right is NullLiteral) {
4844 if (TypeSpec.IsReferenceType (l))
4847 if (l.Kind == MemberKind.InternalCompilerType)
4852 // LAMESPEC: method groups can be compared when they convert to other side delegate
4855 if (right.eclass == ExprClass.MethodGroup) {
4856 result = Convert.ImplicitConversion (ec, right, l, loc);
4862 } else if (r.IsDelegate && l != r) {
4865 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4866 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4873 no_arg_conv = l == r && !l.IsStruct;
4878 // bool operator != (string a, string b)
4879 // bool operator == (string a, string b)
4881 // bool operator != (Delegate a, Delegate b)
4882 // bool operator == (Delegate a, Delegate b)
4884 // bool operator != (bool a, bool b)
4885 // bool operator == (bool a, bool b)
4887 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4888 // they implement an implicit conversion to any of types above. This does
4889 // not apply when both operands are of same reference type
4891 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4892 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4897 // Now try lifted version of predefined operators
4899 if (no_arg_conv && !l.IsNullableType) {
4901 // Optimizes cases which won't match
4904 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4910 // The == and != operators permit one operand to be a value of a nullable
4911 // type and the other to be the null literal, even if no predefined or user-defined
4912 // operator (in unlifted or lifted form) exists for the operation.
4914 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4915 var lifted = new Nullable.LiftedBinaryOperator (this);
4917 lifted.Right = right;
4918 return lifted.Resolve (ec);
4923 // bool operator != (object a, object b)
4924 // bool operator == (object a, object b)
4926 // An explicit reference conversion exists from the
4927 // type of either operand to the type of the other operand.
4930 // Optimize common path
4932 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4935 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4936 !Convert.ExplicitReferenceConversionExists (r, l))
4939 // Reject allowed explicit conversions like int->object
4940 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4943 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4944 ec.Report.Warning (253, 2, loc,
4945 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4946 l.GetSignatureForError ());
4948 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4949 ec.Report.Warning (252, 2, loc,
4950 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4951 r.GetSignatureForError ());
4957 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4960 // bool operator == (void* x, void* y);
4961 // bool operator != (void* x, void* y);
4962 // bool operator < (void* x, void* y);
4963 // bool operator > (void* x, void* y);
4964 // bool operator <= (void* x, void* y);
4965 // bool operator >= (void* x, void* y);
4967 if ((oper & Operator.ComparisonMask) != 0) {
4970 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4977 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4983 type = ec.BuiltinTypes.Bool;
4987 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4991 // Build-in operators method overloading
4993 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4995 PredefinedOperator best_operator = null;
4996 TypeSpec l = left.Type;
4997 TypeSpec r = right.Type;
4998 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5000 foreach (PredefinedOperator po in operators) {
5001 if ((po.OperatorsMask & oper_mask) == 0)
5004 if (primitives_only) {
5005 if (!po.IsPrimitiveApplicable (l, r))
5008 if (!po.IsApplicable (ec, left, right))
5012 if (best_operator == null) {
5014 if (primitives_only)
5020 best_operator = po.ResolveBetterOperator (ec, best_operator);
5022 if (best_operator == null) {
5023 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5024 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5031 if (best_operator == null)
5034 return best_operator.ConvertResult (ec, this);
5038 // Optimize & constant expressions with 0 value
5040 Expression OptimizeAndOperation (Expression expr)
5042 Constant rc = right as Constant;
5043 Constant lc = left as Constant;
5044 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5046 // The result is a constant with side-effect
5048 Constant side_effect = rc == null ?
5049 new SideEffectConstant (lc, right, loc) :
5050 new SideEffectConstant (rc, left, loc);
5052 return ReducedExpression.Create (side_effect, expr);
5059 // Value types can be compared with the null literal because of the lifting
5060 // language rules. However the result is always true or false.
5062 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5064 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5065 type = rc.BuiltinTypes.Bool;
5069 // FIXME: Handle side effect constants
5070 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5072 if ((Oper & Operator.EqualityMask) != 0) {
5073 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5074 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5076 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5077 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5084 // Performs user-operator overloading
5086 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5088 Expression oper_expr;
5090 var op = ConvertBinaryToUserOperator (oper);
5092 if (l.IsNullableType)
5093 l = Nullable.NullableInfo.GetUnderlyingType (l);
5095 if (r.IsNullableType)
5096 r = Nullable.NullableInfo.GetUnderlyingType (r);
5098 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5099 IList<MemberSpec> right_operators = null;
5102 right_operators = MemberCache.GetUserOperator (r, op, false);
5103 if (right_operators == null && left_operators == null)
5105 } else if (left_operators == null) {
5109 Arguments args = new Arguments (2);
5110 Argument larg = new Argument (left);
5112 Argument rarg = new Argument (right);
5116 // User-defined operator implementations always take precedence
5117 // over predefined operator implementations
5119 if (left_operators != null && right_operators != null) {
5120 left_operators = CombineUserOperators (left_operators, right_operators);
5121 } else if (right_operators != null) {
5122 left_operators = right_operators;
5125 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5126 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5128 var res = new OverloadResolver (left_operators, restr, loc);
5130 var oper_method = res.ResolveOperator (rc, ref args);
5131 if (oper_method == null) {
5133 // Logical && and || cannot be lifted
5135 if ((oper & Operator.LogicalMask) != 0)
5139 // Apply lifted user operators only for liftable types. Implicit conversion
5140 // to nullable types is not allowed
5142 if (!IsLiftedOperatorApplicable ())
5145 // TODO: Cache the result in module container
5146 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5147 if (lifted_methods == null)
5150 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5152 oper_method = res.ResolveOperator (rc, ref args);
5153 if (oper_method == null)
5156 MethodSpec best_original = null;
5157 foreach (MethodSpec ms in left_operators) {
5158 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5164 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5166 // Expression trees use lifted notation in this case
5168 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5169 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5172 var ptypes = best_original.Parameters.Types;
5174 if (left.IsNull || right.IsNull) {
5176 // The lifted operator produces a null value if one or both operands are null
5178 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5179 type = oper_method.ReturnType;
5180 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5184 // The lifted operator produces the value false if one or both operands are null for
5185 // relational operators.
5187 if ((oper & Operator.RelationalMask) != 0) {
5189 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5190 // because return type is actually bool
5192 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5195 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5196 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5200 type = oper_method.ReturnType;
5201 var lifted = new Nullable.LiftedBinaryOperator (this);
5202 lifted.UserOperator = best_original;
5204 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5205 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5208 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5209 lifted.UnwrapRight = new Nullable.Unwrap (right);
5212 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5213 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5215 return lifted.Resolve (rc);
5218 if ((oper & Operator.LogicalMask) != 0) {
5219 // TODO: CreateExpressionTree is allocated every time
5220 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5221 oper == Operator.LogicalAnd, loc).Resolve (rc);
5223 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5226 this.left = larg.Expr;
5227 this.right = rarg.Expr;
5232 bool IsLiftedOperatorApplicable ()
5234 if (left.Type.IsNullableType) {
5235 if ((oper & Operator.EqualityMask) != 0)
5236 return !right.IsNull;
5241 if (right.Type.IsNullableType) {
5242 if ((oper & Operator.EqualityMask) != 0)
5243 return !left.IsNull;
5248 if (TypeSpec.IsValueType (left.Type))
5249 return right.IsNull;
5251 if (TypeSpec.IsValueType (right.Type))
5257 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5259 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5260 if (nullable_type == null)
5264 // Lifted operators permit predefined and user-defined operators that operate
5265 // on non-nullable value types to also be used with nullable forms of those types.
5266 // Lifted operators are constructed from predefined and user-defined operators
5267 // that meet certain requirements
5269 List<MemberSpec> lifted = null;
5270 foreach (MethodSpec oper in operators) {
5272 if ((Oper & Operator.ComparisonMask) != 0) {
5274 // Result type must be of type bool for lifted comparison operators
5276 rt = oper.ReturnType;
5277 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5280 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5286 var ptypes = oper.Parameters.Types;
5287 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5291 // LAMESPEC: I am not sure why but for equality operators to be lifted
5292 // both types have to match
5294 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5298 lifted = new List<MemberSpec> ();
5301 // The lifted form is constructed by adding a single ? modifier to each operand and
5302 // result type except for comparison operators where return type is bool
5305 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5307 var parameters = ParametersCompiled.CreateFullyResolved (
5308 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5309 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5311 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5312 rt, parameters, oper.Modifiers);
5314 lifted.Add (lifted_op);
5321 // Merge two sets of user operators into one, they are mostly distinguish
5322 // except when they share base type and it contains an operator
5324 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5326 var combined = new List<MemberSpec> (left.Count + right.Count);
5327 combined.AddRange (left);
5328 foreach (var r in right) {
5330 foreach (var l in left) {
5331 if (l.DeclaringType == r.DeclaringType) {
5344 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5346 if (c is IntegralConstant || c is CharConstant) {
5348 c.ConvertExplicitly (true, type);
5349 } catch (OverflowException) {
5350 ec.Report.Warning (652, 2, loc,
5351 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5352 type.GetSignatureForError ());
5358 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5359 /// context of a conditional bool expression. This function will return
5360 /// false if it is was possible to use EmitBranchable, or true if it was.
5362 /// The expression's code is generated, and we will generate a branch to `target'
5363 /// if the resulting expression value is equal to isTrue
5365 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5367 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5368 left = left.EmitToField (ec);
5370 if ((oper & Operator.LogicalMask) == 0) {
5371 right = right.EmitToField (ec);
5376 // This is more complicated than it looks, but its just to avoid
5377 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5378 // but on top of that we want for == and != to use a special path
5379 // if we are comparing against null
5381 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5382 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5385 // put the constant on the rhs, for simplicity
5387 if (left is Constant) {
5388 Expression swap = right;
5394 // brtrue/brfalse works with native int only
5396 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5397 left.EmitBranchable (ec, target, my_on_true);
5400 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5401 // right is a boolean, and it's not 'false' => it is 'true'
5402 left.EmitBranchable (ec, target, !my_on_true);
5406 } else if (oper == Operator.LogicalAnd) {
5409 Label tests_end = ec.DefineLabel ();
5411 left.EmitBranchable (ec, tests_end, false);
5412 right.EmitBranchable (ec, target, true);
5413 ec.MarkLabel (tests_end);
5416 // This optimizes code like this
5417 // if (true && i > 4)
5419 if (!(left is Constant))
5420 left.EmitBranchable (ec, target, false);
5422 if (!(right is Constant))
5423 right.EmitBranchable (ec, target, false);
5428 } else if (oper == Operator.LogicalOr){
5430 left.EmitBranchable (ec, target, true);
5431 right.EmitBranchable (ec, target, true);
5434 Label tests_end = ec.DefineLabel ();
5435 left.EmitBranchable (ec, tests_end, true);
5436 right.EmitBranchable (ec, target, false);
5437 ec.MarkLabel (tests_end);
5442 } else if ((oper & Operator.ComparisonMask) == 0) {
5443 base.EmitBranchable (ec, target, on_true);
5450 TypeSpec t = left.Type;
5451 bool is_float = IsFloat (t);
5452 bool is_unsigned = is_float || IsUnsigned (t);
5455 case Operator.Equality:
5457 ec.Emit (OpCodes.Beq, target);
5459 ec.Emit (OpCodes.Bne_Un, target);
5462 case Operator.Inequality:
5464 ec.Emit (OpCodes.Bne_Un, target);
5466 ec.Emit (OpCodes.Beq, target);
5469 case Operator.LessThan:
5471 if (is_unsigned && !is_float)
5472 ec.Emit (OpCodes.Blt_Un, target);
5474 ec.Emit (OpCodes.Blt, target);
5477 ec.Emit (OpCodes.Bge_Un, target);
5479 ec.Emit (OpCodes.Bge, target);
5482 case Operator.GreaterThan:
5484 if (is_unsigned && !is_float)
5485 ec.Emit (OpCodes.Bgt_Un, target);
5487 ec.Emit (OpCodes.Bgt, target);
5490 ec.Emit (OpCodes.Ble_Un, target);
5492 ec.Emit (OpCodes.Ble, target);
5495 case Operator.LessThanOrEqual:
5497 if (is_unsigned && !is_float)
5498 ec.Emit (OpCodes.Ble_Un, target);
5500 ec.Emit (OpCodes.Ble, target);
5503 ec.Emit (OpCodes.Bgt_Un, target);
5505 ec.Emit (OpCodes.Bgt, target);
5509 case Operator.GreaterThanOrEqual:
5511 if (is_unsigned && !is_float)
5512 ec.Emit (OpCodes.Bge_Un, target);
5514 ec.Emit (OpCodes.Bge, target);
5517 ec.Emit (OpCodes.Blt_Un, target);
5519 ec.Emit (OpCodes.Blt, target);
5522 throw new InternalErrorException (oper.ToString ());
5526 public override void Emit (EmitContext ec)
5528 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5529 left = left.EmitToField (ec);
5531 if ((oper & Operator.LogicalMask) == 0) {
5532 right = right.EmitToField (ec);
5537 // Handle short-circuit operators differently
5540 if ((oper & Operator.LogicalMask) != 0) {
5541 Label load_result = ec.DefineLabel ();
5542 Label end = ec.DefineLabel ();
5544 bool is_or = oper == Operator.LogicalOr;
5545 left.EmitBranchable (ec, load_result, is_or);
5547 ec.Emit (OpCodes.Br_S, end);
5549 ec.MarkLabel (load_result);
5550 ec.EmitInt (is_or ? 1 : 0);
5556 // Optimize zero-based operations which cannot be optimized at expression level
5558 if (oper == Operator.Subtraction) {
5559 var lc = left as IntegralConstant;
5560 if (lc != null && lc.IsDefaultValue) {
5562 ec.Emit (OpCodes.Neg);
5567 EmitOperator (ec, left, right);
5570 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5575 EmitOperatorOpcode (ec, oper, left.Type, right);
5578 // Emit result enumerable conversion this way because it's quite complicated get it
5579 // to resolved tree because expression tree cannot see it.
5581 if (enum_conversion != 0)
5582 ConvCast.Emit (ec, enum_conversion);
5585 public override void EmitSideEffect (EmitContext ec)
5587 if ((oper & Operator.LogicalMask) != 0 ||
5588 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5589 base.EmitSideEffect (ec);
5591 left.EmitSideEffect (ec);
5592 right.EmitSideEffect (ec);
5596 public override Expression EmitToField (EmitContext ec)
5598 if ((oper & Operator.LogicalMask) == 0) {
5599 var await_expr = left as Await;
5600 if (await_expr != null && right.IsSideEffectFree) {
5601 await_expr.Statement.EmitPrologue (ec);
5602 left = await_expr.Statement.GetResultExpression (ec);
5606 await_expr = right as Await;
5607 if (await_expr != null && left.IsSideEffectFree) {
5608 await_expr.Statement.EmitPrologue (ec);
5609 right = await_expr.Statement.GetResultExpression (ec);
5614 return base.EmitToField (ec);
5617 protected override void CloneTo (CloneContext clonectx, Expression t)
5619 Binary target = (Binary) t;
5621 target.left = left.Clone (clonectx);
5622 target.right = right.Clone (clonectx);
5625 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5627 Arguments binder_args = new Arguments (4);
5629 MemberAccess sle = new MemberAccess (new MemberAccess (
5630 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5632 CSharpBinderFlags flags = 0;
5633 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5634 flags = CSharpBinderFlags.CheckedContext;
5636 if ((oper & Operator.LogicalMask) != 0)
5637 flags |= CSharpBinderFlags.BinaryOperationLogical;
5639 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5640 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5641 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5642 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5644 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5647 public override Expression CreateExpressionTree (ResolveContext ec)
5649 return CreateExpressionTree (ec, null);
5652 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5655 bool lift_arg = false;
5658 case Operator.Addition:
5659 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5660 method_name = "AddChecked";
5662 method_name = "Add";
5664 case Operator.BitwiseAnd:
5665 method_name = "And";
5667 case Operator.BitwiseOr:
5670 case Operator.Division:
5671 method_name = "Divide";
5673 case Operator.Equality:
5674 method_name = "Equal";
5677 case Operator.ExclusiveOr:
5678 method_name = "ExclusiveOr";
5680 case Operator.GreaterThan:
5681 method_name = "GreaterThan";
5684 case Operator.GreaterThanOrEqual:
5685 method_name = "GreaterThanOrEqual";
5688 case Operator.Inequality:
5689 method_name = "NotEqual";
5692 case Operator.LeftShift:
5693 method_name = "LeftShift";
5695 case Operator.LessThan:
5696 method_name = "LessThan";
5699 case Operator.LessThanOrEqual:
5700 method_name = "LessThanOrEqual";
5703 case Operator.LogicalAnd:
5704 method_name = "AndAlso";
5706 case Operator.LogicalOr:
5707 method_name = "OrElse";
5709 case Operator.Modulus:
5710 method_name = "Modulo";
5712 case Operator.Multiply:
5713 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5714 method_name = "MultiplyChecked";
5716 method_name = "Multiply";
5718 case Operator.RightShift:
5719 method_name = "RightShift";
5721 case Operator.Subtraction:
5722 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5723 method_name = "SubtractChecked";
5725 method_name = "Subtract";
5729 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5732 Arguments args = new Arguments (2);
5733 args.Add (new Argument (left.CreateExpressionTree (ec)));
5734 args.Add (new Argument (right.CreateExpressionTree (ec)));
5735 if (method != null) {
5737 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5739 args.Add (new Argument (method));
5742 return CreateExpressionFactoryCall (ec, method_name, args);
5745 public override object Accept (StructuralVisitor visitor)
5747 return visitor.Visit (this);
5753 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5754 // b, c, d... may be strings or objects.
5756 public class StringConcat : Expression
5758 Arguments arguments;
5760 StringConcat (Location loc)
5763 arguments = new Arguments (2);
5766 public override bool ContainsEmitWithAwait ()
5768 return arguments.ContainsEmitWithAwait ();
5771 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5773 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5774 throw new ArgumentException ();
5776 var s = new StringConcat (loc);
5777 s.type = rc.BuiltinTypes.String;
5778 s.eclass = ExprClass.Value;
5780 s.Append (rc, left);
5781 s.Append (rc, right);
5785 public override Expression CreateExpressionTree (ResolveContext ec)
5787 Argument arg = arguments [0];
5788 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5792 // Creates nested calls tree from an array of arguments used for IL emit
5794 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5796 Arguments concat_args = new Arguments (2);
5797 Arguments add_args = new Arguments (3);
5799 concat_args.Add (left);
5800 add_args.Add (new Argument (left_etree));
5802 concat_args.Add (arguments [pos]);
5803 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5805 var methods = GetConcatMethodCandidates ();
5806 if (methods == null)
5809 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5810 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5814 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5816 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5817 if (++pos == arguments.Count)
5820 left = new Argument (new EmptyExpression (method.ReturnType));
5821 return CreateExpressionAddCall (ec, left, expr, pos);
5824 protected override Expression DoResolve (ResolveContext ec)
5829 void Append (ResolveContext rc, Expression operand)
5834 StringConstant sc = operand as StringConstant;
5836 if (arguments.Count != 0) {
5837 Argument last_argument = arguments [arguments.Count - 1];
5838 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5839 if (last_expr_constant != null) {
5840 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5846 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5848 StringConcat concat_oper = operand as StringConcat;
5849 if (concat_oper != null) {
5850 arguments.AddRange (concat_oper.arguments);
5855 arguments.Add (new Argument (operand));
5858 IList<MemberSpec> GetConcatMethodCandidates ()
5860 return MemberCache.FindMembers (type, "Concat", true);
5863 public override void Emit (EmitContext ec)
5865 // Optimize by removing any extra null arguments, they are no-op
5866 for (int i = 0; i < arguments.Count; ++i) {
5867 if (arguments[i].Expr is NullConstant)
5868 arguments.RemoveAt (i--);
5871 var members = GetConcatMethodCandidates ();
5872 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5873 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5874 if (method != null) {
5875 var call = new CallEmitter ();
5876 call.EmitPredefined (ec, method, arguments, false);
5880 public override void FlowAnalysis (FlowAnalysisContext fc)
5882 arguments.FlowAnalysis (fc);
5885 public override SLE.Expression MakeExpression (BuilderContext ctx)
5887 if (arguments.Count != 2)
5888 throw new NotImplementedException ("arguments.Count != 2");
5890 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5891 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5896 // User-defined conditional logical operator
5898 public class ConditionalLogicalOperator : UserOperatorCall
5900 readonly bool is_and;
5901 Expression oper_expr;
5903 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5904 : base (oper, arguments, expr_tree, loc)
5906 this.is_and = is_and;
5907 eclass = ExprClass.Unresolved;
5910 protected override Expression DoResolve (ResolveContext ec)
5912 AParametersCollection pd = oper.Parameters;
5913 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5914 ec.Report.Error (217, loc,
5915 "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",
5916 oper.GetSignatureForError ());
5920 Expression left_dup = new EmptyExpression (type);
5921 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5922 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5923 if (op_true == null || op_false == null) {
5924 ec.Report.Error (218, loc,
5925 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5926 type.GetSignatureForError (), oper.GetSignatureForError ());
5930 oper_expr = is_and ? op_false : op_true;
5931 eclass = ExprClass.Value;
5935 public override void Emit (EmitContext ec)
5937 Label end_target = ec.DefineLabel ();
5940 // Emit and duplicate left argument
5942 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5943 if (right_contains_await) {
5944 arguments[0] = arguments[0].EmitToField (ec, false);
5945 arguments[0].Expr.Emit (ec);
5947 arguments[0].Expr.Emit (ec);
5948 ec.Emit (OpCodes.Dup);
5949 arguments.RemoveAt (0);
5952 oper_expr.EmitBranchable (ec, end_target, true);
5956 if (right_contains_await) {
5958 // Special handling when right expression contains await and left argument
5959 // could not be left on stack before logical branch
5961 Label skip_left_load = ec.DefineLabel ();
5962 ec.Emit (OpCodes.Br_S, skip_left_load);
5963 ec.MarkLabel (end_target);
5964 arguments[0].Expr.Emit (ec);
5965 ec.MarkLabel (skip_left_load);
5967 ec.MarkLabel (end_target);
5972 public class PointerArithmetic : Expression {
5973 Expression left, right;
5974 readonly Binary.Operator op;
5977 // We assume that `l' is always a pointer
5979 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5988 public override bool ContainsEmitWithAwait ()
5990 throw new NotImplementedException ();
5993 public override Expression CreateExpressionTree (ResolveContext ec)
5995 Error_PointerInsideExpressionTree (ec);
5999 protected override Expression DoResolve (ResolveContext ec)
6001 eclass = ExprClass.Variable;
6003 var pc = left.Type as PointerContainer;
6004 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6005 Error_VoidPointerOperation (ec);
6012 public override void Emit (EmitContext ec)
6014 TypeSpec op_type = left.Type;
6016 // It must be either array or fixed buffer
6018 if (TypeManager.HasElementType (op_type)) {
6019 element = TypeManager.GetElementType (op_type);
6021 FieldExpr fe = left as FieldExpr;
6023 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6028 int size = BuiltinTypeSpec.GetSize(element);
6029 TypeSpec rtype = right.Type;
6031 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6033 // handle (pointer - pointer)
6037 ec.Emit (OpCodes.Sub);
6041 ec.Emit (OpCodes.Sizeof, element);
6044 ec.Emit (OpCodes.Div);
6046 ec.Emit (OpCodes.Conv_I8);
6049 // handle + and - on (pointer op int)
6051 Constant left_const = left as Constant;
6052 if (left_const != null) {
6054 // Optimize ((T*)null) pointer operations
6056 if (left_const.IsDefaultValue) {
6057 left = EmptyExpression.Null;
6065 var right_const = right as Constant;
6066 if (right_const != null) {
6068 // Optimize 0-based arithmetic
6070 if (right_const.IsDefaultValue)
6074 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6076 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6078 // TODO: Should be the checks resolve context sensitive?
6079 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6080 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6086 if (right_const == null) {
6087 switch (rtype.BuiltinType) {
6088 case BuiltinTypeSpec.Type.SByte:
6089 case BuiltinTypeSpec.Type.Byte:
6090 case BuiltinTypeSpec.Type.Short:
6091 case BuiltinTypeSpec.Type.UShort:
6092 case BuiltinTypeSpec.Type.Int:
6093 ec.Emit (OpCodes.Conv_I);
6095 case BuiltinTypeSpec.Type.UInt:
6096 ec.Emit (OpCodes.Conv_U);
6101 if (right_const == null && size != 1){
6103 ec.Emit (OpCodes.Sizeof, element);
6106 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6107 ec.Emit (OpCodes.Conv_I8);
6109 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6112 if (left_const == null) {
6113 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6114 ec.Emit (OpCodes.Conv_I);
6115 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6116 ec.Emit (OpCodes.Conv_U);
6118 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6125 // A boolean-expression is an expression that yields a result
6128 public class BooleanExpression : ShimExpression
6130 public BooleanExpression (Expression expr)
6133 this.loc = expr.Location;
6136 public override Expression CreateExpressionTree (ResolveContext ec)
6138 // TODO: We should emit IsTrue (v4) instead of direct user operator
6139 // call but that would break csc compatibility
6140 return base.CreateExpressionTree (ec);
6143 protected override Expression DoResolve (ResolveContext ec)
6145 // A boolean-expression is required to be of a type
6146 // that can be implicitly converted to bool or of
6147 // a type that implements operator true
6149 expr = expr.Resolve (ec);
6153 Assign ass = expr as Assign;
6154 if (ass != null && ass.Source is Constant) {
6155 ec.Report.Warning (665, 3, loc,
6156 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6159 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6162 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6163 Arguments args = new Arguments (1);
6164 args.Add (new Argument (expr));
6165 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6168 type = ec.BuiltinTypes.Bool;
6169 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6170 if (converted != null)
6174 // If no implicit conversion to bool exists, try using `operator true'
6176 converted = GetOperatorTrue (ec, expr, loc);
6177 if (converted == null) {
6178 expr.Error_ValueCannotBeConverted (ec, type, false);
6185 public override object Accept (StructuralVisitor visitor)
6187 return visitor.Visit (this);
6191 public class BooleanExpressionFalse : Unary
6193 public BooleanExpressionFalse (Expression expr)
6194 : base (Operator.LogicalNot, expr, expr.Location)
6198 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6200 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6205 /// Implements the ternary conditional operator (?:)
6207 public class Conditional : Expression {
6208 Expression expr, true_expr, false_expr;
6210 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6213 this.true_expr = true_expr;
6214 this.false_expr = false_expr;
6220 public Expression Expr {
6226 public Expression TrueExpr {
6232 public Expression FalseExpr {
6240 public override bool ContainsEmitWithAwait ()
6242 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6245 public override Expression CreateExpressionTree (ResolveContext ec)
6247 Arguments args = new Arguments (3);
6248 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6249 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6250 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6251 return CreateExpressionFactoryCall (ec, "Condition", args);
6254 protected override Expression DoResolve (ResolveContext ec)
6256 expr = expr.Resolve (ec);
6257 true_expr = true_expr.Resolve (ec);
6258 false_expr = false_expr.Resolve (ec);
6260 if (true_expr == null || false_expr == null || expr == null)
6263 eclass = ExprClass.Value;
6264 TypeSpec true_type = true_expr.Type;
6265 TypeSpec false_type = false_expr.Type;
6269 // First, if an implicit conversion exists from true_expr
6270 // to false_expr, then the result type is of type false_expr.Type
6272 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6273 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6274 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6276 // Check if both can convert implicitly to each other's type
6280 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6281 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6283 // LAMESPEC: There seems to be hardcoded promotition to int type when
6284 // both sides are numeric constants and one side is int constant and
6285 // other side is numeric constant convertible to int.
6287 // var res = condition ? (short)1 : 1;
6289 // Type of res is int even if according to the spec the conversion is
6290 // ambiguous because 1 literal can be converted to short.
6292 if (conv_false_expr != null) {
6293 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6295 conv_false_expr = null;
6296 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6297 conv_false_expr = null;
6301 if (conv_false_expr != null) {
6302 ec.Report.Error (172, true_expr.Location,
6303 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6304 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6309 if (true_expr.Type != type)
6310 true_expr = EmptyCast.Create (true_expr, type);
6311 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6314 if (false_type != InternalType.ErrorType) {
6315 ec.Report.Error (173, true_expr.Location,
6316 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6317 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6323 Constant c = expr as Constant;
6325 bool is_false = c.IsDefaultValue;
6328 // Don't issue the warning for constant expressions
6330 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6331 // CSC: Missing warning
6332 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6335 return ReducedExpression.Create (
6336 is_false ? false_expr : true_expr, this,
6337 false_expr is Constant && true_expr is Constant).Resolve (ec);
6343 public override void Emit (EmitContext ec)
6345 Label false_target = ec.DefineLabel ();
6346 Label end_target = ec.DefineLabel ();
6348 expr.EmitBranchable (ec, false_target, false);
6349 true_expr.Emit (ec);
6352 // Verifier doesn't support interface merging. When there are two types on
6353 // the stack without common type hint and the common type is an interface.
6354 // Use temporary local to give verifier hint on what type to unify the stack
6356 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6357 var temp = ec.GetTemporaryLocal (type);
6358 ec.Emit (OpCodes.Stloc, temp);
6359 ec.Emit (OpCodes.Ldloc, temp);
6360 ec.FreeTemporaryLocal (temp, type);
6363 ec.Emit (OpCodes.Br, end_target);
6364 ec.MarkLabel (false_target);
6365 false_expr.Emit (ec);
6366 ec.MarkLabel (end_target);
6369 public override void FlowAnalysis (FlowAnalysisContext fc)
6371 expr.FlowAnalysisConditional (fc);
6372 var expr_true = fc.DefiniteAssignmentOnTrue;
6373 var expr_false = fc.DefiniteAssignmentOnFalse;
6375 fc.BranchDefiniteAssignment (expr_true);
6376 true_expr.FlowAnalysis (fc);
6377 var true_fc = fc.DefiniteAssignment;
6379 fc.BranchDefiniteAssignment (expr_false);
6380 false_expr.FlowAnalysis (fc);
6382 fc.DefiniteAssignment &= true_fc;
6385 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6387 expr.FlowAnalysisConditional (fc);
6388 var expr_true = fc.DefiniteAssignmentOnTrue;
6389 var expr_false = fc.DefiniteAssignmentOnFalse;
6391 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6392 true_expr.FlowAnalysisConditional (fc);
6393 var true_fc = fc.DefiniteAssignment;
6394 var true_da_true = fc.DefiniteAssignmentOnTrue;
6395 var true_da_false = fc.DefiniteAssignmentOnFalse;
6397 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6398 false_expr.FlowAnalysisConditional (fc);
6400 fc.DefiniteAssignment &= true_fc;
6401 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6402 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6405 protected override void CloneTo (CloneContext clonectx, Expression t)
6407 Conditional target = (Conditional) t;
6409 target.expr = expr.Clone (clonectx);
6410 target.true_expr = true_expr.Clone (clonectx);
6411 target.false_expr = false_expr.Clone (clonectx);
6415 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6417 LocalTemporary temp;
6420 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6421 public abstract void SetHasAddressTaken ();
6423 public abstract bool IsLockedByStatement { get; set; }
6425 public abstract bool IsFixed { get; }
6426 public abstract bool IsRef { get; }
6427 public abstract string Name { get; }
6430 // Variable IL data, it has to be protected to encapsulate hoisted variables
6432 protected abstract ILocalVariable Variable { get; }
6435 // Variable flow-analysis data
6437 public abstract VariableInfo VariableInfo { get; }
6440 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6442 HoistedVariable hv = GetHoistedVariable (ec);
6444 hv.AddressOf (ec, mode);
6448 Variable.EmitAddressOf (ec);
6451 public override bool ContainsEmitWithAwait ()
6456 public override Expression CreateExpressionTree (ResolveContext ec)
6458 HoistedVariable hv = GetHoistedVariable (ec);
6460 return hv.CreateExpressionTree ();
6462 Arguments arg = new Arguments (1);
6463 arg.Add (new Argument (this));
6464 return CreateExpressionFactoryCall (ec, "Constant", arg);
6467 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6469 if (IsLockedByStatement) {
6470 rc.Report.Warning (728, 2, loc,
6471 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6478 public override void Emit (EmitContext ec)
6483 public override void EmitSideEffect (EmitContext ec)
6489 // This method is used by parameters that are references, that are
6490 // being passed as references: we only want to pass the pointer (that
6491 // is already stored in the parameter, not the address of the pointer,
6492 // and not the value of the variable).
6494 public void EmitLoad (EmitContext ec)
6499 public void Emit (EmitContext ec, bool leave_copy)
6501 HoistedVariable hv = GetHoistedVariable (ec);
6503 hv.Emit (ec, leave_copy);
6511 // If we are a reference, we loaded on the stack a pointer
6512 // Now lets load the real value
6514 ec.EmitLoadFromPtr (type);
6518 ec.Emit (OpCodes.Dup);
6521 temp = new LocalTemporary (Type);
6527 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6528 bool prepare_for_load)
6530 HoistedVariable hv = GetHoistedVariable (ec);
6532 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6536 New n_source = source as New;
6537 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6538 if (!n_source.Emit (ec, this)) {
6542 ec.EmitLoadFromPtr (type);
6554 ec.Emit (OpCodes.Dup);
6556 temp = new LocalTemporary (Type);
6562 ec.EmitStoreFromPtr (type);
6564 Variable.EmitAssign (ec);
6572 public override Expression EmitToField (EmitContext ec)
6574 HoistedVariable hv = GetHoistedVariable (ec);
6576 return hv.EmitToField (ec);
6579 return base.EmitToField (ec);
6582 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6584 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6587 public HoistedVariable GetHoistedVariable (EmitContext ec)
6589 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6592 public override string GetSignatureForError ()
6597 public bool IsHoisted {
6598 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6603 // Resolved reference to a local variable
6605 public class LocalVariableReference : VariableReference
6607 public LocalVariable local_info;
6609 public LocalVariableReference (LocalVariable li, Location l)
6611 this.local_info = li;
6615 public override VariableInfo VariableInfo {
6616 get { return local_info.VariableInfo; }
6619 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6621 return local_info.HoistedVariant;
6627 // A local variable is always fixed
6629 public override bool IsFixed {
6635 public override bool IsLockedByStatement {
6637 return local_info.IsLocked;
6640 local_info.IsLocked = value;
6644 public override bool IsRef {
6645 get { return false; }
6648 public override string Name {
6649 get { return local_info.Name; }
6654 public override void FlowAnalysis (FlowAnalysisContext fc)
6656 VariableInfo variable_info = VariableInfo;
6657 if (variable_info == null)
6660 if (fc.IsDefinitelyAssigned (variable_info))
6663 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6664 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6667 public override void SetHasAddressTaken ()
6669 local_info.SetHasAddressTaken ();
6672 void DoResolveBase (ResolveContext ec)
6674 eclass = ExprClass.Variable;
6675 type = local_info.Type;
6678 // If we are referencing a variable from the external block
6679 // flag it for capturing
6681 if (ec.MustCaptureVariable (local_info)) {
6682 if (local_info.AddressTaken) {
6683 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6684 } else if (local_info.IsFixed) {
6685 ec.Report.Error (1764, loc,
6686 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6687 GetSignatureForError ());
6690 if (ec.IsVariableCapturingRequired) {
6691 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6692 storey.CaptureLocalVariable (ec, local_info);
6697 protected override Expression DoResolve (ResolveContext ec)
6699 local_info.SetIsUsed ();
6703 if (local_info.Type == InternalType.VarOutType) {
6704 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6705 GetSignatureForError ());
6707 type = InternalType.ErrorType;
6713 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6716 // Don't be too pedantic when variable is used as out param or for some broken code
6717 // which uses property/indexer access to run some initialization
6719 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6720 local_info.SetIsUsed ();
6722 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6723 if (rhs == EmptyExpression.LValueMemberAccess) {
6724 // CS1654 already reported
6728 if (rhs == EmptyExpression.OutAccess) {
6729 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6730 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6731 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6732 } else if (rhs == EmptyExpression.UnaryAddress) {
6733 code = 459; msg = "Cannot take the address of {1} `{0}'";
6735 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6737 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6741 if (eclass == ExprClass.Unresolved)
6744 return base.DoResolveLValue (ec, rhs);
6747 public override int GetHashCode ()
6749 return local_info.GetHashCode ();
6752 public override bool Equals (object obj)
6754 LocalVariableReference lvr = obj as LocalVariableReference;
6758 return local_info == lvr.local_info;
6761 protected override ILocalVariable Variable {
6762 get { return local_info; }
6765 public override string ToString ()
6767 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6770 protected override void CloneTo (CloneContext clonectx, Expression t)
6777 /// This represents a reference to a parameter in the intermediate
6780 public class ParameterReference : VariableReference
6782 protected ParametersBlock.ParameterInfo pi;
6784 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6792 public override bool IsLockedByStatement {
6797 pi.IsLocked = value;
6801 public override bool IsRef {
6802 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6805 bool HasOutModifier {
6806 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6809 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6811 return pi.Parameter.HoistedVariant;
6815 // A ref or out parameter is classified as a moveable variable, even
6816 // if the argument given for the parameter is a fixed variable
6818 public override bool IsFixed {
6819 get { return !IsRef; }
6822 public override string Name {
6823 get { return Parameter.Name; }
6826 public Parameter Parameter {
6827 get { return pi.Parameter; }
6830 public override VariableInfo VariableInfo {
6831 get { return pi.VariableInfo; }
6834 protected override ILocalVariable Variable {
6835 get { return Parameter; }
6840 public override void AddressOf (EmitContext ec, AddressOp mode)
6843 // ParameterReferences might already be a reference
6850 base.AddressOf (ec, mode);
6853 public override void SetHasAddressTaken ()
6855 Parameter.HasAddressTaken = true;
6858 bool DoResolveBase (ResolveContext ec)
6860 if (eclass != ExprClass.Unresolved)
6863 type = pi.ParameterType;
6864 eclass = ExprClass.Variable;
6867 // If we are referencing a parameter from the external block
6868 // flag it for capturing
6870 if (ec.MustCaptureVariable (pi)) {
6871 if (Parameter.HasAddressTaken)
6872 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6875 ec.Report.Error (1628, loc,
6876 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6877 Name, ec.CurrentAnonymousMethod.ContainerType);
6880 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6881 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6882 storey.CaptureParameter (ec, pi, this);
6889 public override int GetHashCode ()
6891 return Name.GetHashCode ();
6894 public override bool Equals (object obj)
6896 ParameterReference pr = obj as ParameterReference;
6900 return Name == pr.Name;
6903 protected override void CloneTo (CloneContext clonectx, Expression target)
6909 public override Expression CreateExpressionTree (ResolveContext ec)
6911 HoistedVariable hv = GetHoistedVariable (ec);
6913 return hv.CreateExpressionTree ();
6915 return Parameter.ExpressionTreeVariableReference ();
6918 protected override Expression DoResolve (ResolveContext ec)
6920 if (!DoResolveBase (ec))
6926 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6928 if (!DoResolveBase (ec))
6931 if (Parameter.HoistedVariant != null)
6932 Parameter.HoistedVariant.IsAssigned = true;
6934 return base.DoResolveLValue (ec, right_side);
6937 public override void FlowAnalysis (FlowAnalysisContext fc)
6939 VariableInfo variable_info = VariableInfo;
6940 if (variable_info == null)
6943 if (fc.IsDefinitelyAssigned (variable_info))
6946 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6947 fc.SetVariableAssigned (variable_info);
6952 /// Invocation of methods or delegates.
6954 public class Invocation : ExpressionStatement
6956 public class Predefined : Invocation
6958 public Predefined (MethodGroupExpr expr, Arguments arguments)
6959 : base (expr, arguments)
6964 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6966 mg.BestCandidate.CheckObsoleteness (rc, loc);
6972 protected Arguments arguments;
6973 protected Expression expr;
6974 protected MethodGroupExpr mg;
6975 bool conditional_access_receiver;
6977 public Invocation (Expression expr, Arguments arguments)
6980 this.arguments = arguments;
6982 loc = expr.Location;
6987 public Arguments Arguments {
6993 public Expression Exp {
6999 public MethodGroupExpr MethodGroup {
7005 public override Location StartLocation {
7007 return expr.StartLocation;
7013 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7015 if (MethodGroup == null)
7018 var candidate = MethodGroup.BestCandidate;
7019 if (candidate == null || !(candidate.IsStatic || Exp is This))
7022 var args_count = arguments == null ? 0 : arguments.Count;
7023 if (args_count != body.Parameters.Count)
7026 var lambda_parameters = body.Block.Parameters.FixedParameters;
7027 for (int i = 0; i < args_count; ++i) {
7028 var pr = arguments[i].Expr as ParameterReference;
7032 if (lambda_parameters[i] != pr.Parameter)
7035 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7039 var emg = MethodGroup as ExtensionMethodGroupExpr;
7041 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7042 if (candidate.IsGeneric) {
7043 var targs = new TypeExpression [candidate.Arity];
7044 for (int i = 0; i < targs.Length; ++i) {
7045 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7048 mg.SetTypeArguments (null, new TypeArguments (targs));
7057 protected override void CloneTo (CloneContext clonectx, Expression t)
7059 Invocation target = (Invocation) t;
7061 if (arguments != null)
7062 target.arguments = arguments.Clone (clonectx);
7064 target.expr = expr.Clone (clonectx);
7067 public override bool ContainsEmitWithAwait ()
7069 if (arguments != null && arguments.ContainsEmitWithAwait ())
7072 return mg.ContainsEmitWithAwait ();
7075 public override Expression CreateExpressionTree (ResolveContext ec)
7077 Expression instance = mg.IsInstance ?
7078 mg.InstanceExpression.CreateExpressionTree (ec) :
7079 new NullLiteral (loc);
7081 var args = Arguments.CreateForExpressionTree (ec, arguments,
7083 mg.CreateExpressionTree (ec));
7085 return CreateExpressionFactoryCall (ec, "Call", args);
7088 void ResolveConditionalAccessReceiver (ResolveContext rc)
7090 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7091 conditional_access_receiver = true;
7095 bool statement_resolve;
7096 public override ExpressionStatement ResolveStatement (BlockContext bc)
7098 statement_resolve = true;
7099 var es = base.ResolveStatement (bc);
7100 statement_resolve = false;
7105 protected override Expression DoResolve (ResolveContext rc)
7107 ResolveConditionalAccessReceiver (rc);
7108 return DoResolveInvocation (rc);
7111 Expression DoResolveInvocation (ResolveContext ec)
7113 Expression member_expr;
7114 var atn = expr as ATypeNameExpression;
7116 var flags = default (ResolveContext.FlagsHandle);
7117 if (conditional_access_receiver)
7118 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7121 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7122 if (member_expr != null) {
7123 var name_of = member_expr as NameOf;
7124 if (name_of != null) {
7125 return name_of.ResolveOverload (ec, arguments);
7128 member_expr = member_expr.Resolve (ec);
7131 member_expr = expr.Resolve (ec);
7134 if (conditional_access_receiver)
7137 if (member_expr == null)
7141 // Next, evaluate all the expressions in the argument list
7143 bool dynamic_arg = false;
7144 if (arguments != null) {
7145 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7146 arguments.Resolve (ec, out dynamic_arg);
7150 TypeSpec expr_type = member_expr.Type;
7151 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7152 return DoResolveDynamic (ec, member_expr);
7154 mg = member_expr as MethodGroupExpr;
7155 Expression invoke = null;
7158 if (expr_type != null && expr_type.IsDelegate) {
7159 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7160 invoke = invoke.Resolve (ec);
7161 if (invoke == null || !dynamic_arg)
7164 if (member_expr is RuntimeValueExpression) {
7165 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7166 member_expr.Type.GetSignatureForError ());
7170 MemberExpr me = member_expr as MemberExpr;
7172 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7176 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7177 member_expr.GetSignatureForError ());
7182 if (invoke == null) {
7183 mg = DoResolveOverload (ec);
7189 return DoResolveDynamic (ec, member_expr);
7191 var method = mg.BestCandidate;
7192 type = mg.BestCandidateReturnType;
7193 if (conditional_access_receiver && !statement_resolve)
7194 type = LiftMemberType (ec, type);
7196 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7198 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7200 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7204 IsSpecialMethodInvocation (ec, method, loc);
7206 eclass = ExprClass.Value;
7210 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7213 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7215 args = dmb.Arguments;
7216 if (arguments != null)
7217 args.AddRange (arguments);
7218 } else if (mg == null) {
7219 if (arguments == null)
7220 args = new Arguments (1);
7224 args.Insert (0, new Argument (memberExpr));
7228 ec.Report.Error (1971, loc,
7229 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7234 if (arguments == null)
7235 args = new Arguments (1);
7239 MemberAccess ma = expr as MemberAccess;
7241 var inst = mg.InstanceExpression;
7242 var left_type = inst as TypeExpr;
7243 if (left_type != null) {
7244 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7245 } else if (inst != null) {
7247 // Any value type has to be pass as by-ref to get back the same
7248 // instance on which the member was called
7250 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7251 Argument.AType.Ref : Argument.AType.None;
7252 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7254 } else { // is SimpleName
7255 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7256 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7258 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7263 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7266 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7268 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7271 public override void FlowAnalysis (FlowAnalysisContext fc)
7273 if (mg.IsConditionallyExcluded)
7276 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7278 mg.FlowAnalysis (fc);
7280 if (arguments != null)
7281 arguments.FlowAnalysis (fc);
7283 if (conditional_access_receiver)
7284 fc.DefiniteAssignment = da;
7287 public override string GetSignatureForError ()
7289 return mg.GetSignatureForError ();
7292 public override bool HasConditionalAccess ()
7294 return expr.HasConditionalAccess ();
7298 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7299 // or the type dynamic, then the member is invocable
7301 public static bool IsMemberInvocable (MemberSpec member)
7303 switch (member.Kind) {
7304 case MemberKind.Event:
7306 case MemberKind.Field:
7307 case MemberKind.Property:
7308 var m = member as IInterfaceMemberSpec;
7309 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7315 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7317 if (!method.IsReservedMethod)
7320 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7323 ec.Report.SymbolRelatedToPreviousError (method);
7324 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7325 method.GetSignatureForError ());
7330 public override void Emit (EmitContext ec)
7332 if (mg.IsConditionallyExcluded)
7335 if (conditional_access_receiver)
7336 mg.EmitCall (ec, arguments, type, false);
7338 mg.EmitCall (ec, arguments, false);
7341 public override void EmitStatement (EmitContext ec)
7343 if (mg.IsConditionallyExcluded)
7346 if (conditional_access_receiver)
7347 mg.EmitCall (ec, arguments, type, true);
7349 mg.EmitCall (ec, arguments, true);
7352 public override SLE.Expression MakeExpression (BuilderContext ctx)
7354 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7357 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7360 throw new NotSupportedException ();
7362 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7363 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7367 public override object Accept (StructuralVisitor visitor)
7369 return visitor.Visit (this);
7374 // Implements simple new expression
7376 public class New : ExpressionStatement, IMemoryLocation
7378 protected Arguments arguments;
7381 // During bootstrap, it contains the RequestedType,
7382 // but if `type' is not null, it *might* contain a NewDelegate
7383 // (because of field multi-initialization)
7385 protected Expression RequestedType;
7387 protected MethodSpec method;
7389 public New (Expression requested_type, Arguments arguments, Location l)
7391 RequestedType = requested_type;
7392 this.arguments = arguments;
7397 public Arguments Arguments {
7404 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7406 public bool IsGeneratedStructConstructor {
7408 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7412 public Expression TypeExpression {
7414 return RequestedType;
7421 /// Converts complex core type syntax like 'new int ()' to simple constant
7423 public static Constant Constantify (TypeSpec t, Location loc)
7425 switch (t.BuiltinType) {
7426 case BuiltinTypeSpec.Type.Int:
7427 return new IntConstant (t, 0, loc);
7428 case BuiltinTypeSpec.Type.UInt:
7429 return new UIntConstant (t, 0, loc);
7430 case BuiltinTypeSpec.Type.Long:
7431 return new LongConstant (t, 0, loc);
7432 case BuiltinTypeSpec.Type.ULong:
7433 return new ULongConstant (t, 0, loc);
7434 case BuiltinTypeSpec.Type.Float:
7435 return new FloatConstant (t, 0, loc);
7436 case BuiltinTypeSpec.Type.Double:
7437 return new DoubleConstant (t, 0, loc);
7438 case BuiltinTypeSpec.Type.Short:
7439 return new ShortConstant (t, 0, loc);
7440 case BuiltinTypeSpec.Type.UShort:
7441 return new UShortConstant (t, 0, loc);
7442 case BuiltinTypeSpec.Type.SByte:
7443 return new SByteConstant (t, 0, loc);
7444 case BuiltinTypeSpec.Type.Byte:
7445 return new ByteConstant (t, 0, loc);
7446 case BuiltinTypeSpec.Type.Char:
7447 return new CharConstant (t, '\0', loc);
7448 case BuiltinTypeSpec.Type.Bool:
7449 return new BoolConstant (t, false, loc);
7450 case BuiltinTypeSpec.Type.Decimal:
7451 return new DecimalConstant (t, 0, loc);
7455 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7457 if (t.IsNullableType)
7458 return Nullable.LiftedNull.Create (t, loc);
7463 public override bool ContainsEmitWithAwait ()
7465 return arguments != null && arguments.ContainsEmitWithAwait ();
7469 // Checks whether the type is an interface that has the
7470 // [ComImport, CoClass] attributes and must be treated
7473 public Expression CheckComImport (ResolveContext ec)
7475 if (!type.IsInterface)
7479 // Turn the call into:
7480 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7482 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7483 if (real_class == null)
7486 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7487 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7488 return cast.Resolve (ec);
7491 public override Expression CreateExpressionTree (ResolveContext ec)
7494 if (method == null) {
7495 args = new Arguments (1);
7496 args.Add (new Argument (new TypeOf (type, loc)));
7498 args = Arguments.CreateForExpressionTree (ec,
7499 arguments, new TypeOfMethod (method, loc));
7502 return CreateExpressionFactoryCall (ec, "New", args);
7505 protected override Expression DoResolve (ResolveContext ec)
7507 type = RequestedType.ResolveAsType (ec);
7511 eclass = ExprClass.Value;
7513 if (type.IsPointer) {
7514 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7515 type.GetSignatureForError ());
7519 if (arguments == null) {
7520 Constant c = Constantify (type, RequestedType.Location);
7522 return ReducedExpression.Create (c, this);
7525 if (type.IsDelegate) {
7526 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7529 var tparam = type as TypeParameterSpec;
7530 if (tparam != null) {
7532 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7533 // where type parameter constraint is inflated to struct
7535 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7536 ec.Report.Error (304, loc,
7537 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7538 type.GetSignatureForError ());
7541 if ((arguments != null) && (arguments.Count != 0)) {
7542 ec.Report.Error (417, loc,
7543 "`{0}': cannot provide arguments when creating an instance of a variable type",
7544 type.GetSignatureForError ());
7550 if (type.IsStatic) {
7551 ec.Report.SymbolRelatedToPreviousError (type);
7552 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7556 if (type.IsInterface || type.IsAbstract){
7557 if (!TypeManager.IsGenericType (type)) {
7558 RequestedType = CheckComImport (ec);
7559 if (RequestedType != null)
7560 return RequestedType;
7563 ec.Report.SymbolRelatedToPreviousError (type);
7564 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7569 if (arguments != null) {
7570 arguments.Resolve (ec, out dynamic);
7575 method = ConstructorLookup (ec, type, ref arguments, loc);
7578 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7579 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7585 void DoEmitTypeParameter (EmitContext ec)
7587 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7591 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7592 ec.Emit (OpCodes.Call, ctor_factory);
7596 // This Emit can be invoked in two contexts:
7597 // * As a mechanism that will leave a value on the stack (new object)
7598 // * As one that wont (init struct)
7600 // If we are dealing with a ValueType, we have a few
7601 // situations to deal with:
7603 // * The target is a ValueType, and we have been provided
7604 // the instance (this is easy, we are being assigned).
7606 // * The target of New is being passed as an argument,
7607 // to a boxing operation or a function that takes a
7610 // In this case, we need to create a temporary variable
7611 // that is the argument of New.
7613 // Returns whether a value is left on the stack
7615 // *** Implementation note ***
7617 // To benefit from this optimization, each assignable expression
7618 // has to manually cast to New and call this Emit.
7620 // TODO: It's worth to implement it for arrays and fields
7622 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7624 bool is_value_type = type.IsStructOrEnum;
7625 VariableReference vr = target as VariableReference;
7627 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7629 if (target != null && is_value_type && (vr != null || method == null)) {
7630 if (prepare_await) {
7631 arguments = arguments.Emit (ec, false, true);
7632 prepare_await = false;
7635 target.AddressOf (ec, AddressOp.Store);
7636 } else if (vr != null && vr.IsRef) {
7640 if (arguments != null) {
7642 arguments = arguments.Emit (ec, false, true);
7644 arguments.Emit (ec);
7647 if (is_value_type) {
7648 if (method == null) {
7649 ec.Emit (OpCodes.Initobj, type);
7654 ec.MarkCallEntry (loc);
7655 ec.Emit (OpCodes.Call, method);
7660 if (type is TypeParameterSpec) {
7661 DoEmitTypeParameter (ec);
7665 ec.MarkCallEntry (loc);
7666 ec.Emit (OpCodes.Newobj, method);
7670 public override void Emit (EmitContext ec)
7672 LocalTemporary v = null;
7673 if (method == null && type.IsStructOrEnum) {
7674 // TODO: Use temporary variable from pool
7675 v = new LocalTemporary (type);
7682 public override void EmitStatement (EmitContext ec)
7684 LocalTemporary v = null;
7685 if (method == null && TypeSpec.IsValueType (type)) {
7686 // TODO: Use temporary variable from pool
7687 v = new LocalTemporary (type);
7691 ec.Emit (OpCodes.Pop);
7694 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7699 public override void FlowAnalysis (FlowAnalysisContext fc)
7701 if (arguments != null)
7702 arguments.FlowAnalysis (fc);
7705 public void AddressOf (EmitContext ec, AddressOp mode)
7707 EmitAddressOf (ec, mode);
7710 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7712 LocalTemporary value_target = new LocalTemporary (type);
7714 if (type is TypeParameterSpec) {
7715 DoEmitTypeParameter (ec);
7716 value_target.Store (ec);
7717 value_target.AddressOf (ec, mode);
7718 return value_target;
7721 value_target.AddressOf (ec, AddressOp.Store);
7723 if (method == null) {
7724 ec.Emit (OpCodes.Initobj, type);
7726 if (arguments != null)
7727 arguments.Emit (ec);
7729 ec.Emit (OpCodes.Call, method);
7732 value_target.AddressOf (ec, mode);
7733 return value_target;
7736 protected override void CloneTo (CloneContext clonectx, Expression t)
7738 New target = (New) t;
7740 target.RequestedType = RequestedType.Clone (clonectx);
7741 if (arguments != null){
7742 target.arguments = arguments.Clone (clonectx);
7746 public override SLE.Expression MakeExpression (BuilderContext ctx)
7749 return base.MakeExpression (ctx);
7751 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7755 public override object Accept (StructuralVisitor visitor)
7757 return visitor.Visit (this);
7762 // Array initializer expression, the expression is allowed in
7763 // variable or field initialization only which makes it tricky as
7764 // the type has to be infered based on the context either from field
7765 // type or variable type (think of multiple declarators)
7767 public class ArrayInitializer : Expression
7769 List<Expression> elements;
7770 BlockVariable variable;
7772 public ArrayInitializer (List<Expression> init, Location loc)
7778 public ArrayInitializer (int count, Location loc)
7779 : this (new List<Expression> (count), loc)
7783 public ArrayInitializer (Location loc)
7791 get { return elements.Count; }
7794 public List<Expression> Elements {
7800 public Expression this [int index] {
7802 return elements [index];
7806 public BlockVariable VariableDeclaration {
7817 public void Add (Expression expr)
7819 elements.Add (expr);
7822 public override bool ContainsEmitWithAwait ()
7824 throw new NotSupportedException ();
7827 public override Expression CreateExpressionTree (ResolveContext ec)
7829 throw new NotSupportedException ("ET");
7832 protected override void CloneTo (CloneContext clonectx, Expression t)
7834 var target = (ArrayInitializer) t;
7836 target.elements = new List<Expression> (elements.Count);
7837 foreach (var element in elements)
7838 target.elements.Add (element.Clone (clonectx));
7841 protected override Expression DoResolve (ResolveContext rc)
7843 var current_field = rc.CurrentMemberDefinition as FieldBase;
7844 TypeExpression type;
7845 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7846 type = new TypeExpression (current_field.MemberType, current_field.Location);
7847 } else if (variable != null) {
7848 if (variable.TypeExpression is VarExpr) {
7849 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7850 return EmptyExpression.Null;
7853 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7855 throw new NotImplementedException ("Unexpected array initializer context");
7858 return new ArrayCreation (type, this).Resolve (rc);
7861 public override void Emit (EmitContext ec)
7863 throw new InternalErrorException ("Missing Resolve call");
7866 public override void FlowAnalysis (FlowAnalysisContext fc)
7868 throw new InternalErrorException ("Missing Resolve call");
7871 public override object Accept (StructuralVisitor visitor)
7873 return visitor.Visit (this);
7878 /// 14.5.10.2: Represents an array creation expression.
7882 /// There are two possible scenarios here: one is an array creation
7883 /// expression that specifies the dimensions and optionally the
7884 /// initialization data and the other which does not need dimensions
7885 /// specified but where initialization data is mandatory.
7887 public class ArrayCreation : Expression
7889 FullNamedExpression requested_base_type;
7890 ArrayInitializer initializers;
7893 // The list of Argument types.
7894 // This is used to construct the `newarray' or constructor signature
7896 protected List<Expression> arguments;
7898 protected TypeSpec array_element_type;
7900 protected int dimensions;
7901 protected readonly ComposedTypeSpecifier rank;
7902 Expression first_emit;
7903 LocalTemporary first_emit_temp;
7905 protected List<Expression> array_data;
7907 Dictionary<int, int> bounds;
7910 // The number of constants in array initializers
7911 int const_initializers_count;
7912 bool only_constant_initializers;
7914 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7915 : this (requested_base_type, rank, initializers, l)
7917 arguments = new List<Expression> (exprs);
7918 num_arguments = arguments.Count;
7922 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7924 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7926 this.requested_base_type = requested_base_type;
7928 this.initializers = initializers;
7932 num_arguments = rank.Dimension;
7936 // For compiler generated single dimensional arrays only
7938 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7939 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7944 // For expressions like int[] foo = { 1, 2, 3 };
7946 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7947 : this (requested_base_type, null, initializers, initializers.Location)
7951 public bool NoEmptyInterpolation { get; set; }
7953 public ComposedTypeSpecifier Rank {
7959 public FullNamedExpression TypeExpression {
7961 return this.requested_base_type;
7965 public ArrayInitializer Initializers {
7967 return this.initializers;
7971 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7973 if (initializers != null && bounds == null) {
7975 // We use this to store all the data values in the order in which we
7976 // will need to store them in the byte blob later
7978 array_data = new List<Expression> (probe.Count);
7979 bounds = new Dictionary<int, int> ();
7982 if (specified_dims) {
7983 Expression a = arguments [idx];
7988 a = ConvertExpressionToArrayIndex (ec, a);
7994 if (initializers != null) {
7995 Constant c = a as Constant;
7996 if (c == null && a is ArrayIndexCast)
7997 c = ((ArrayIndexCast) a).Child as Constant;
8000 ec.Report.Error (150, a.Location, "A constant value is expected");
8006 value = System.Convert.ToInt32 (c.GetValue ());
8008 ec.Report.Error (150, a.Location, "A constant value is expected");
8012 // TODO: probe.Count does not fit ulong in
8013 if (value != probe.Count) {
8014 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8018 bounds[idx] = value;
8022 if (initializers == null)
8025 for (int i = 0; i < probe.Count; ++i) {
8027 if (o is ArrayInitializer) {
8028 var sub_probe = o as ArrayInitializer;
8029 if (idx + 1 >= dimensions){
8030 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8034 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8035 if (!bounds.ContainsKey(idx + 1))
8036 bounds[idx + 1] = sub_probe.Count;
8038 if (bounds[idx + 1] != sub_probe.Count) {
8039 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8043 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8046 } else if (child_bounds > 1) {
8047 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8049 Expression element = ResolveArrayElement (ec, o);
8050 if (element == null)
8053 // Initializers with the default values can be ignored
8054 Constant c = element as Constant;
8056 if (!c.IsDefaultInitializer (array_element_type)) {
8057 ++const_initializers_count;
8060 only_constant_initializers = false;
8063 array_data.Add (element);
8070 public override bool ContainsEmitWithAwait ()
8072 foreach (var arg in arguments) {
8073 if (arg.ContainsEmitWithAwait ())
8077 return InitializersContainAwait ();
8080 public override Expression CreateExpressionTree (ResolveContext ec)
8084 if (array_data == null) {
8085 args = new Arguments (arguments.Count + 1);
8086 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8087 foreach (Expression a in arguments)
8088 args.Add (new Argument (a.CreateExpressionTree (ec)));
8090 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8093 if (dimensions > 1) {
8094 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8098 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8099 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8100 if (array_data != null) {
8101 for (int i = 0; i < array_data.Count; ++i) {
8102 Expression e = array_data [i];
8103 args.Add (new Argument (e.CreateExpressionTree (ec)));
8107 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8110 void UpdateIndices (ResolveContext rc)
8113 for (var probe = initializers; probe != null;) {
8114 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8116 bounds[i++] = probe.Count;
8118 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8119 probe = (ArrayInitializer) probe[0];
8120 } else if (dimensions > i) {
8128 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8130 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8133 public override void FlowAnalysis (FlowAnalysisContext fc)
8135 foreach (var arg in arguments)
8136 arg.FlowAnalysis (fc);
8138 if (array_data != null) {
8139 foreach (var ad in array_data)
8140 ad.FlowAnalysis (fc);
8144 bool InitializersContainAwait ()
8146 if (array_data == null)
8149 foreach (var expr in array_data) {
8150 if (expr.ContainsEmitWithAwait ())
8157 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8159 element = element.Resolve (ec);
8160 if (element == null)
8163 var te = element as CompoundAssign.TargetExpression;
8165 for (int i = 1; i < initializers.Count; ++i) {
8166 if (initializers [i].ContainsEmitWithAwait ()) {
8167 te.RequiresEmitWithAwait = true;
8172 if (!te.RequiresEmitWithAwait) {
8173 if (first_emit != null)
8174 throw new InternalErrorException ("Can only handle one mutator at a time");
8175 first_emit = element;
8176 element = first_emit_temp = new LocalTemporary (element.Type);
8180 return Convert.ImplicitConversionRequired (
8181 ec, element, array_element_type, loc);
8184 protected bool ResolveInitializers (ResolveContext ec)
8187 only_constant_initializers = true;
8190 if (arguments != null) {
8192 for (int i = 0; i < arguments.Count; ++i) {
8193 res &= CheckIndices (ec, initializers, i, true, dimensions);
8194 if (initializers != null)
8201 arguments = new List<Expression> ();
8203 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8212 // Resolved the type of the array
8214 bool ResolveArrayType (ResolveContext ec)
8219 FullNamedExpression array_type_expr;
8220 if (num_arguments > 0) {
8221 array_type_expr = new ComposedCast (requested_base_type, rank);
8223 array_type_expr = requested_base_type;
8226 type = array_type_expr.ResolveAsType (ec);
8227 if (array_type_expr == null)
8230 var ac = type as ArrayContainer;
8232 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8236 array_element_type = ac.Element;
8237 dimensions = ac.Rank;
8242 protected override Expression DoResolve (ResolveContext ec)
8247 if (!ResolveArrayType (ec))
8251 // validate the initializers and fill in any missing bits
8253 if (!ResolveInitializers (ec))
8256 eclass = ExprClass.Value;
8260 byte [] MakeByteBlob ()
8265 int count = array_data.Count;
8267 TypeSpec element_type = array_element_type;
8268 if (element_type.IsEnum)
8269 element_type = EnumSpec.GetUnderlyingType (element_type);
8271 factor = BuiltinTypeSpec.GetSize (element_type);
8273 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8275 data = new byte [(count * factor + 3) & ~3];
8278 for (int i = 0; i < count; ++i) {
8279 var c = array_data[i] as Constant;
8285 object v = c.GetValue ();
8287 switch (element_type.BuiltinType) {
8288 case BuiltinTypeSpec.Type.Long:
8289 long lval = (long) v;
8291 for (int j = 0; j < factor; ++j) {
8292 data[idx + j] = (byte) (lval & 0xFF);
8296 case BuiltinTypeSpec.Type.ULong:
8297 ulong ulval = (ulong) v;
8299 for (int j = 0; j < factor; ++j) {
8300 data[idx + j] = (byte) (ulval & 0xFF);
8301 ulval = (ulval >> 8);
8304 case BuiltinTypeSpec.Type.Float:
8305 var fval = SingleConverter.SingleToInt32Bits((float) v);
8307 data[idx] = (byte) (fval & 0xff);
8308 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8309 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8310 data[idx + 3] = (byte) (fval >> 24);
8312 case BuiltinTypeSpec.Type.Double:
8313 element = BitConverter.GetBytes ((double) v);
8315 for (int j = 0; j < factor; ++j)
8316 data[idx + j] = element[j];
8318 // FIXME: Handle the ARM float format.
8319 if (!BitConverter.IsLittleEndian)
8320 System.Array.Reverse (data, idx, 8);
8322 case BuiltinTypeSpec.Type.Char:
8323 int chval = (int) ((char) v);
8325 data[idx] = (byte) (chval & 0xff);
8326 data[idx + 1] = (byte) (chval >> 8);
8328 case BuiltinTypeSpec.Type.Short:
8329 int sval = (int) ((short) v);
8331 data[idx] = (byte) (sval & 0xff);
8332 data[idx + 1] = (byte) (sval >> 8);
8334 case BuiltinTypeSpec.Type.UShort:
8335 int usval = (int) ((ushort) v);
8337 data[idx] = (byte) (usval & 0xff);
8338 data[idx + 1] = (byte) (usval >> 8);
8340 case BuiltinTypeSpec.Type.Int:
8343 data[idx] = (byte) (val & 0xff);
8344 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8345 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8346 data[idx + 3] = (byte) (val >> 24);
8348 case BuiltinTypeSpec.Type.UInt:
8349 uint uval = (uint) v;
8351 data[idx] = (byte) (uval & 0xff);
8352 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8353 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8354 data[idx + 3] = (byte) (uval >> 24);
8356 case BuiltinTypeSpec.Type.SByte:
8357 data[idx] = (byte) (sbyte) v;
8359 case BuiltinTypeSpec.Type.Byte:
8360 data[idx] = (byte) v;
8362 case BuiltinTypeSpec.Type.Bool:
8363 data[idx] = (byte) ((bool) v ? 1 : 0);
8365 case BuiltinTypeSpec.Type.Decimal:
8366 int[] bits = Decimal.GetBits ((decimal) v);
8369 // FIXME: For some reason, this doesn't work on the MS runtime.
8370 int[] nbits = new int[4];
8376 for (int j = 0; j < 4; j++) {
8377 data[p++] = (byte) (nbits[j] & 0xff);
8378 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8379 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8380 data[p++] = (byte) (nbits[j] >> 24);
8384 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8393 public override SLE.Expression MakeExpression (BuilderContext ctx)
8396 return base.MakeExpression (ctx);
8398 var initializers = new SLE.Expression [array_data.Count];
8399 for (var i = 0; i < initializers.Length; i++) {
8400 if (array_data [i] == null)
8401 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8403 initializers [i] = array_data [i].MakeExpression (ctx);
8406 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8411 // Emits the initializers for the array
8413 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8415 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8420 // First, the static data
8422 byte [] data = MakeByteBlob ();
8423 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8425 if (stackArray == null) {
8426 ec.Emit (OpCodes.Dup);
8428 stackArray.Emit (ec);
8431 ec.Emit (OpCodes.Ldtoken, fb);
8432 ec.Emit (OpCodes.Call, m);
8437 // Emits pieces of the array that can not be computed at compile
8438 // time (variables and string locations).
8440 // This always expect the top value on the stack to be the array
8442 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8444 int dims = bounds.Count;
8445 var current_pos = new int [dims];
8447 for (int i = 0; i < array_data.Count; i++){
8449 Expression e = array_data [i];
8450 var c = e as Constant;
8452 // Constant can be initialized via StaticInitializer
8453 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8457 if (stackArray != null) {
8458 if (e.ContainsEmitWithAwait ()) {
8459 e = e.EmitToField (ec);
8462 stackArray.EmitLoad (ec);
8464 ec.Emit (OpCodes.Dup);
8467 for (int idx = 0; idx < dims; idx++)
8468 ec.EmitInt (current_pos [idx]);
8471 // If we are dealing with a struct, get the
8472 // address of it, so we can store it.
8474 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8475 ec.Emit (OpCodes.Ldelema, etype);
8479 ec.EmitArrayStore ((ArrayContainer) type);
8485 for (int j = dims - 1; j >= 0; j--){
8487 if (current_pos [j] < bounds [j])
8489 current_pos [j] = 0;
8493 if (stackArray != null)
8494 stackArray.PrepareCleanup (ec);
8497 public override void Emit (EmitContext ec)
8499 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8502 var await_field = EmitToFieldSource (ec);
8503 if (await_field != null)
8504 await_field.Emit (ec);
8507 bool EmitOptimizedEmpty (EmitContext ec)
8509 if (arguments.Count != 1 || dimensions != 1)
8512 var c = arguments [0] as Constant;
8513 if (c == null || !c.IsZeroInteger)
8516 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8517 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8520 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8521 ec.Emit (OpCodes.Call, m);
8525 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8527 if (first_emit != null) {
8528 first_emit.Emit (ec);
8529 first_emit_temp.Store (ec);
8532 StackFieldExpr await_stack_field;
8533 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8534 await_stack_field = ec.GetTemporaryField (type);
8537 await_stack_field = null;
8540 EmitExpressionsList (ec, arguments);
8542 ec.EmitArrayNew ((ArrayContainer) type);
8544 if (initializers == null)
8545 return await_stack_field;
8547 if (await_stack_field != null)
8548 await_stack_field.EmitAssignFromStack (ec);
8552 // Emit static initializer for arrays which contain more than 2 items and
8553 // the static initializer will initialize at least 25% of array values or there
8554 // is more than 10 items to be initialized
8556 // NOTE: const_initializers_count does not contain default constant values.
8558 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8559 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8560 EmitStaticInitializers (ec, await_stack_field);
8562 if (!only_constant_initializers)
8563 EmitDynamicInitializers (ec, false, await_stack_field);
8567 EmitDynamicInitializers (ec, true, await_stack_field);
8570 if (first_emit_temp != null)
8571 first_emit_temp.Release (ec);
8573 return await_stack_field;
8576 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8578 // no multi dimensional or jagged arrays
8579 if (arguments.Count != 1 || array_element_type.IsArray) {
8580 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8584 // No array covariance, except for array -> object
8585 if (type != targetType) {
8586 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8587 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8591 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8592 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8597 // Single dimensional array of 0 size
8598 if (array_data == null) {
8599 IntConstant ic = arguments[0] as IntConstant;
8600 if (ic == null || !ic.IsDefaultValue) {
8601 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8609 enc.Encode (array_data.Count);
8610 foreach (var element in array_data) {
8611 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8615 protected override void CloneTo (CloneContext clonectx, Expression t)
8617 ArrayCreation target = (ArrayCreation) t;
8619 if (requested_base_type != null)
8620 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8622 if (arguments != null){
8623 target.arguments = new List<Expression> (arguments.Count);
8624 foreach (Expression e in arguments)
8625 target.arguments.Add (e.Clone (clonectx));
8628 if (initializers != null)
8629 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8632 public override object Accept (StructuralVisitor visitor)
8634 return visitor.Visit (this);
8639 // Represents an implicitly typed array epxression
8641 class ImplicitlyTypedArrayCreation : ArrayCreation
8643 TypeInferenceContext best_type_inference;
8645 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8646 : base (null, rank, initializers, loc)
8650 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8651 : base (null, initializers, loc)
8655 protected override Expression DoResolve (ResolveContext ec)
8660 dimensions = rank.Dimension;
8662 best_type_inference = new TypeInferenceContext ();
8664 if (!ResolveInitializers (ec))
8667 best_type_inference.FixAllTypes (ec);
8668 array_element_type = best_type_inference.InferredTypeArguments[0];
8669 best_type_inference = null;
8671 if (array_element_type == null ||
8672 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8673 arguments.Count != rank.Dimension) {
8674 ec.Report.Error (826, loc,
8675 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8680 // At this point we found common base type for all initializer elements
8681 // but we have to be sure that all static initializer elements are of
8684 UnifyInitializerElement (ec);
8686 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8687 eclass = ExprClass.Value;
8692 // Converts static initializer only
8694 void UnifyInitializerElement (ResolveContext ec)
8696 for (int i = 0; i < array_data.Count; ++i) {
8697 Expression e = array_data[i];
8699 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8703 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8705 element = element.Resolve (ec);
8706 if (element != null)
8707 best_type_inference.AddCommonTypeBound (element.Type);
8713 sealed class CompilerGeneratedThis : This
8715 public CompilerGeneratedThis (TypeSpec type, Location loc)
8721 protected override Expression DoResolve (ResolveContext rc)
8723 eclass = ExprClass.Variable;
8725 var block = rc.CurrentBlock;
8726 if (block != null) {
8727 var top = block.ParametersBlock.TopBlock;
8728 if (top.ThisVariable != null)
8729 variable_info = top.ThisVariable.VariableInfo;
8736 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8738 return DoResolve (rc);
8741 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8748 /// Represents the `this' construct
8751 public class This : VariableReference
8753 sealed class ThisVariable : ILocalVariable
8755 public static readonly ILocalVariable Instance = new ThisVariable ();
8757 public void Emit (EmitContext ec)
8762 public void EmitAssign (EmitContext ec)
8764 throw new InvalidOperationException ();
8767 public void EmitAddressOf (EmitContext ec)
8773 protected VariableInfo variable_info;
8775 public This (Location loc)
8782 public override string Name {
8783 get { return "this"; }
8786 public override bool IsLockedByStatement {
8794 public override bool IsRef {
8795 get { return type.IsStruct; }
8798 public override bool IsSideEffectFree {
8804 protected override ILocalVariable Variable {
8805 get { return ThisVariable.Instance; }
8808 public override VariableInfo VariableInfo {
8809 get { return variable_info; }
8812 public override bool IsFixed {
8813 get { return false; }
8818 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8821 // It's null for all cases when we don't need to check `this'
8822 // definitive assignment
8824 if (variable_info == null)
8827 if (fc.IsDefinitelyAssigned (variable_info))
8830 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8833 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8835 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8836 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8837 } else if (ec.CurrentAnonymousMethod != null) {
8838 ec.Report.Error (1673, loc,
8839 "Anonymous methods inside structs cannot access instance members of `this'. " +
8840 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8842 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8846 public override void FlowAnalysis (FlowAnalysisContext fc)
8848 CheckStructThisDefiniteAssignment (fc);
8851 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8856 AnonymousMethodStorey storey = ae.Storey;
8857 return storey != null ? storey.HoistedThis : null;
8860 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8862 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8865 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8868 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8874 public virtual void ResolveBase (ResolveContext ec)
8876 eclass = ExprClass.Variable;
8877 type = ec.CurrentType;
8879 if (!IsThisAvailable (ec, false)) {
8880 Error_ThisNotAvailable (ec);
8884 var block = ec.CurrentBlock;
8885 if (block != null) {
8886 var top = block.ParametersBlock.TopBlock;
8887 if (top.ThisVariable != null)
8888 variable_info = top.ThisVariable.VariableInfo;
8890 AnonymousExpression am = ec.CurrentAnonymousMethod;
8891 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8893 // Hoisted this is almost like hoisted variable but not exactly. When
8894 // there is no variable hoisted we can simply emit an instance method
8895 // without lifting this into a storey. Unfotunatelly this complicates
8896 // things in other cases because we don't know where this will be hoisted
8897 // until top-level block is fully resolved
8899 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8900 am.SetHasThisAccess ();
8905 protected override Expression DoResolve (ResolveContext ec)
8911 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8913 if (eclass == ExprClass.Unresolved)
8917 if (right_side == EmptyExpression.UnaryAddress)
8918 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8919 else if (right_side == EmptyExpression.OutAccess)
8920 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8922 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8928 public override int GetHashCode()
8930 throw new NotImplementedException ();
8933 public override bool Equals (object obj)
8935 This t = obj as This;
8942 protected override void CloneTo (CloneContext clonectx, Expression t)
8947 public override void SetHasAddressTaken ()
8952 public override object Accept (StructuralVisitor visitor)
8954 return visitor.Visit (this);
8959 /// Represents the `__arglist' construct
8961 public class ArglistAccess : Expression
8963 public ArglistAccess (Location loc)
8968 protected override void CloneTo (CloneContext clonectx, Expression target)
8973 public override bool ContainsEmitWithAwait ()
8978 public override Expression CreateExpressionTree (ResolveContext ec)
8980 throw new NotSupportedException ("ET");
8983 protected override Expression DoResolve (ResolveContext ec)
8985 eclass = ExprClass.Variable;
8986 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8988 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8989 ec.Report.Error (190, loc,
8990 "The __arglist construct is valid only within a variable argument method");
8996 public override void Emit (EmitContext ec)
8998 ec.Emit (OpCodes.Arglist);
9001 public override object Accept (StructuralVisitor visitor)
9003 return visitor.Visit (this);
9008 /// Represents the `__arglist (....)' construct
9010 public class Arglist : Expression
9012 Arguments arguments;
9014 public Arglist (Location loc)
9019 public Arglist (Arguments args, Location l)
9025 public Arguments Arguments {
9031 public MetaType[] ArgumentTypes {
9033 if (arguments == null)
9034 return MetaType.EmptyTypes;
9036 var retval = new MetaType[arguments.Count];
9037 for (int i = 0; i < retval.Length; i++)
9038 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9044 public override bool ContainsEmitWithAwait ()
9046 throw new NotImplementedException ();
9049 public override Expression CreateExpressionTree (ResolveContext ec)
9051 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9055 protected override Expression DoResolve (ResolveContext ec)
9057 eclass = ExprClass.Variable;
9058 type = InternalType.Arglist;
9059 if (arguments != null) {
9060 bool dynamic; // Can be ignored as there is always only 1 overload
9061 arguments.Resolve (ec, out dynamic);
9067 public override void Emit (EmitContext ec)
9069 if (arguments != null)
9070 arguments.Emit (ec);
9073 protected override void CloneTo (CloneContext clonectx, Expression t)
9075 Arglist target = (Arglist) t;
9077 if (arguments != null)
9078 target.arguments = arguments.Clone (clonectx);
9081 public override object Accept (StructuralVisitor visitor)
9083 return visitor.Visit (this);
9087 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9089 FullNamedExpression texpr;
9091 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9098 public FullNamedExpression TypeExpression {
9104 public override bool ContainsEmitWithAwait ()
9109 public void AddressOf (EmitContext ec, AddressOp mode)
9112 ec.Emit (OpCodes.Refanyval, type);
9115 protected override Expression DoResolve (ResolveContext rc)
9117 expr = expr.Resolve (rc);
9118 type = texpr.ResolveAsType (rc);
9119 if (expr == null || type == null)
9122 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9123 eclass = ExprClass.Variable;
9127 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9129 return DoResolve (rc);
9132 public override void Emit (EmitContext ec)
9135 ec.Emit (OpCodes.Refanyval, type);
9136 ec.EmitLoadFromPtr (type);
9139 public void Emit (EmitContext ec, bool leave_copy)
9141 throw new NotImplementedException ();
9144 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9147 ec.Emit (OpCodes.Refanyval, type);
9150 LocalTemporary temporary = null;
9152 ec.Emit (OpCodes.Dup);
9153 temporary = new LocalTemporary (source.Type);
9154 temporary.Store (ec);
9157 ec.EmitStoreFromPtr (type);
9159 if (temporary != null) {
9160 temporary.Emit (ec);
9161 temporary.Release (ec);
9165 public override object Accept (StructuralVisitor visitor)
9167 return visitor.Visit (this);
9171 public class RefTypeExpr : ShimExpression
9173 public RefTypeExpr (Expression expr, Location loc)
9179 protected override Expression DoResolve (ResolveContext rc)
9181 expr = expr.Resolve (rc);
9185 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9189 type = rc.BuiltinTypes.Type;
9190 eclass = ExprClass.Value;
9194 public override void Emit (EmitContext ec)
9197 ec.Emit (OpCodes.Refanytype);
9198 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9200 ec.Emit (OpCodes.Call, m);
9203 public override object Accept (StructuralVisitor visitor)
9205 return visitor.Visit (this);
9209 public class MakeRefExpr : ShimExpression
9211 public MakeRefExpr (Expression expr, Location loc)
9217 public override bool ContainsEmitWithAwait ()
9219 throw new NotImplementedException ();
9222 protected override Expression DoResolve (ResolveContext rc)
9224 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9225 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9226 eclass = ExprClass.Value;
9230 public override void Emit (EmitContext ec)
9232 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9233 ec.Emit (OpCodes.Mkrefany, expr.Type);
9236 public override object Accept (StructuralVisitor visitor)
9238 return visitor.Visit (this);
9243 /// Implements the typeof operator
9245 public class TypeOf : Expression {
9246 FullNamedExpression QueriedType;
9249 public TypeOf (FullNamedExpression queried_type, Location l)
9251 QueriedType = queried_type;
9256 // Use this constructor for any compiler generated typeof expression
9258 public TypeOf (TypeSpec type, Location loc)
9260 this.typearg = type;
9266 public override bool IsSideEffectFree {
9272 public TypeSpec TypeArgument {
9278 public FullNamedExpression TypeExpression {
9287 protected override void CloneTo (CloneContext clonectx, Expression t)
9289 TypeOf target = (TypeOf) t;
9290 if (QueriedType != null)
9291 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9294 public override bool ContainsEmitWithAwait ()
9299 public override Expression CreateExpressionTree (ResolveContext ec)
9301 Arguments args = new Arguments (2);
9302 args.Add (new Argument (this));
9303 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9304 return CreateExpressionFactoryCall (ec, "Constant", args);
9307 protected override Expression DoResolve (ResolveContext ec)
9309 if (eclass != ExprClass.Unresolved)
9312 if (typearg == null) {
9314 // Pointer types are allowed without explicit unsafe, they are just tokens
9316 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9317 typearg = QueriedType.ResolveAsType (ec, true);
9320 if (typearg == null)
9323 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9324 ec.Report.Error (1962, QueriedType.Location,
9325 "The typeof operator cannot be used on the dynamic type");
9329 type = ec.BuiltinTypes.Type;
9331 // Even though what is returned is a type object, it's treated as a value by the compiler.
9332 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9333 eclass = ExprClass.Value;
9337 static bool ContainsDynamicType (TypeSpec type)
9339 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9342 var element_container = type as ElementTypeSpec;
9343 if (element_container != null)
9344 return ContainsDynamicType (element_container.Element);
9346 foreach (var t in type.TypeArguments) {
9347 if (ContainsDynamicType (t)) {
9355 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9357 // Target type is not System.Type therefore must be object
9358 // and we need to use different encoding sequence
9359 if (targetType != type)
9362 if (typearg is InflatedTypeSpec) {
9365 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9366 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9367 typearg.GetSignatureForError ());
9371 gt = gt.DeclaringType;
9372 } while (gt != null);
9375 if (ContainsDynamicType (typearg)) {
9376 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9380 enc.EncodeTypeName (typearg);
9383 public override void Emit (EmitContext ec)
9385 ec.Emit (OpCodes.Ldtoken, typearg);
9386 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9388 ec.Emit (OpCodes.Call, m);
9391 public override object Accept (StructuralVisitor visitor)
9393 return visitor.Visit (this);
9397 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9399 public TypeOfMethod (MethodSpec method, Location loc)
9400 : base (method, loc)
9404 protected override Expression DoResolve (ResolveContext ec)
9406 if (member.IsConstructor) {
9407 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9409 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9415 return base.DoResolve (ec);
9418 public override void Emit (EmitContext ec)
9420 ec.Emit (OpCodes.Ldtoken, member);
9423 ec.Emit (OpCodes.Castclass, type);
9426 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9428 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9431 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9433 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9437 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9439 protected readonly T member;
9441 protected TypeOfMember (T member, Location loc)
9443 this.member = member;
9447 public override bool IsSideEffectFree {
9453 public override bool ContainsEmitWithAwait ()
9458 public override Expression CreateExpressionTree (ResolveContext ec)
9460 Arguments args = new Arguments (2);
9461 args.Add (new Argument (this));
9462 args.Add (new Argument (new TypeOf (type, loc)));
9463 return CreateExpressionFactoryCall (ec, "Constant", args);
9466 protected override Expression DoResolve (ResolveContext ec)
9468 eclass = ExprClass.Value;
9472 public override void Emit (EmitContext ec)
9474 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9475 PredefinedMember<MethodSpec> p;
9477 p = GetTypeFromHandleGeneric (ec);
9478 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9480 p = GetTypeFromHandle (ec);
9483 var mi = p.Resolve (loc);
9485 ec.Emit (OpCodes.Call, mi);
9488 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9489 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9492 sealed class TypeOfField : TypeOfMember<FieldSpec>
9494 public TypeOfField (FieldSpec field, Location loc)
9499 protected override Expression DoResolve (ResolveContext ec)
9501 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9505 return base.DoResolve (ec);
9508 public override void Emit (EmitContext ec)
9510 ec.Emit (OpCodes.Ldtoken, member);
9514 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9516 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9519 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9521 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9526 /// Implements the sizeof expression
9528 public class SizeOf : Expression {
9529 readonly Expression texpr;
9530 TypeSpec type_queried;
9532 public SizeOf (Expression queried_type, Location l)
9534 this.texpr = queried_type;
9538 public override bool IsSideEffectFree {
9544 public Expression TypeExpression {
9550 public override bool ContainsEmitWithAwait ()
9555 public override Expression CreateExpressionTree (ResolveContext ec)
9557 Error_PointerInsideExpressionTree (ec);
9561 protected override Expression DoResolve (ResolveContext ec)
9563 type_queried = texpr.ResolveAsType (ec);
9564 if (type_queried == null)
9567 if (type_queried.IsEnum)
9568 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9570 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9572 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9575 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9580 ec.Report.Error (233, loc,
9581 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9582 type_queried.GetSignatureForError ());
9585 type = ec.BuiltinTypes.Int;
9586 eclass = ExprClass.Value;
9590 public override void Emit (EmitContext ec)
9592 ec.Emit (OpCodes.Sizeof, type_queried);
9595 protected override void CloneTo (CloneContext clonectx, Expression t)
9599 public override object Accept (StructuralVisitor visitor)
9601 return visitor.Visit (this);
9606 /// Implements the qualified-alias-member (::) expression.
9608 public class QualifiedAliasMember : MemberAccess
9610 readonly string alias;
9611 public static readonly string GlobalAlias = "global";
9613 public QualifiedAliasMember (string alias, string identifier, Location l)
9614 : base (null, identifier, l)
9619 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9620 : base (null, identifier, targs, l)
9625 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9626 : base (null, identifier, arity, l)
9631 public string Alias {
9637 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9639 if (alias == GlobalAlias)
9640 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9642 int errors = mc.Module.Compiler.Report.Errors;
9643 var expr = mc.LookupNamespaceAlias (alias);
9645 if (errors == mc.Module.Compiler.Report.Errors)
9646 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9654 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9656 expr = CreateExpressionFromAlias (mc);
9660 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9663 protected override Expression DoResolve (ResolveContext rc)
9665 return ResolveAsTypeOrNamespace (rc, false);
9668 public override string GetSignatureForError ()
9671 if (targs != null) {
9672 name = Name + "<" + targs.GetSignatureForError () + ">";
9675 return alias + "::" + name;
9678 public override bool HasConditionalAccess ()
9683 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9685 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9686 rc.Module.Compiler.Report.Error (687, loc,
9687 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9688 GetSignatureForError ());
9693 return DoResolve (rc);
9696 protected override void CloneTo (CloneContext clonectx, Expression t)
9701 public override object Accept (StructuralVisitor visitor)
9703 return visitor.Visit (this);
9708 /// Implements the member access expression
9710 public class MemberAccess : ATypeNameExpression
9712 protected Expression expr;
9714 public MemberAccess (Expression expr, string id)
9715 : base (id, expr.Location)
9720 public MemberAccess (Expression expr, string identifier, Location loc)
9721 : base (identifier, loc)
9726 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9727 : base (identifier, args, loc)
9732 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9733 : base (identifier, arity, loc)
9738 public Expression LeftExpression {
9744 public override Location StartLocation {
9746 return expr == null ? loc : expr.StartLocation;
9750 protected override Expression DoResolve (ResolveContext rc)
9752 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9754 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9759 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9761 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9763 if (e is TypeExpr) {
9764 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9769 e = e.ResolveLValue (rc, rhs);
9774 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9776 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9777 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9779 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9782 public override bool HasConditionalAccess ()
9784 return LeftExpression.HasConditionalAccess ();
9787 public static bool IsValidDotExpression (TypeSpec type)
9789 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9790 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9792 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9795 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9797 var sn = expr as SimpleName;
9798 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9801 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9804 // Resolve expression which does have type set as we need expression type
9805 // with disable flow analysis as we don't know whether left side expression
9806 // is used as variable or type
9808 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9809 expr = expr.Resolve (rc);
9810 } else if (expr is TypeParameterExpr) {
9811 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9815 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9816 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9817 expr = expr.Resolve (rc, flags);
9820 expr = expr.Resolve (rc, flags);
9827 var ns = expr as NamespaceExpression;
9829 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9831 if (retval == null) {
9832 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9837 if (HasTypeArguments)
9838 return new GenericTypeExpr (retval.Type, targs, loc);
9840 targs.Resolve (rc, false);
9846 var cma = this as ConditionalMemberAccess;
9849 TypeSpec expr_type = expr.Type;
9850 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9851 me = expr as MemberExpr;
9853 me.ResolveInstanceExpression (rc, null);
9855 Arguments args = new Arguments (1);
9856 args.Add (new Argument (expr));
9859 return new DynamicConditionalMemberBinder (Name, args, loc);
9861 return new DynamicMemberBinder (Name, args, loc);
9865 if (!IsNullPropagatingValid (expr.Type)) {
9866 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9870 if (expr_type.IsNullableType) {
9871 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9872 expr_type = expr.Type;
9876 if (!IsValidDotExpression (expr_type)) {
9877 Error_OperatorCannotBeApplied (rc, expr_type);
9881 var lookup_arity = Arity;
9882 bool errorMode = false;
9883 Expression member_lookup;
9885 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9886 if (member_lookup == null) {
9888 // Try to look for extension method when member lookup failed
9890 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9891 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9892 if (methods != null) {
9893 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9894 if (HasTypeArguments) {
9895 if (!targs.Resolve (rc, false))
9898 emg.SetTypeArguments (rc, targs);
9902 emg.ConditionalAccess = true;
9904 // TODO: it should really skip the checks bellow
9905 return emg.Resolve (rc);
9911 if (member_lookup == null) {
9912 var dep = expr_type.GetMissingDependencies ();
9914 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9915 } else if (expr is TypeExpr) {
9916 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9918 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9924 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9925 // Leave it to overload resolution to report correct error
9926 } else if (!(member_lookup is TypeExpr)) {
9927 // TODO: rc.SymbolRelatedToPreviousError
9928 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9933 if (member_lookup != null)
9937 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9941 TypeExpr texpr = member_lookup as TypeExpr;
9942 if (texpr != null) {
9943 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9944 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9945 Name, texpr.GetSignatureForError ());
9948 if (!texpr.Type.IsAccessible (rc)) {
9949 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9950 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9954 if (HasTypeArguments) {
9955 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9958 return member_lookup;
9961 me = member_lookup as MemberExpr;
9963 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9968 me.ConditionalAccess = true;
9971 me = me.ResolveMemberAccess (rc, expr, sn);
9974 if (!targs.Resolve (rc, false))
9977 me.SetTypeArguments (rc, targs);
9983 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9985 FullNamedExpression fexpr = expr as FullNamedExpression;
9986 if (fexpr == null) {
9987 expr.ResolveAsType (rc);
9991 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9993 if (expr_resolved == null)
9996 var ns = expr_resolved as NamespaceExpression;
9998 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10000 if (retval == null) {
10001 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10002 } else if (Arity > 0) {
10003 if (HasTypeArguments) {
10004 retval = new GenericTypeExpr (retval.Type, targs, loc);
10005 if (retval.ResolveAsType (rc) == null)
10008 targs.Resolve (rc, allowUnboundTypeArguments);
10010 retval = new GenericOpenTypeExpr (retval.Type, loc);
10017 var tnew_expr = expr_resolved.ResolveAsType (rc);
10018 if (tnew_expr == null)
10021 TypeSpec expr_type = tnew_expr;
10022 if (TypeManager.IsGenericParameter (expr_type)) {
10023 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10024 tnew_expr.GetSignatureForError ());
10028 var qam = this as QualifiedAliasMember;
10030 rc.Module.Compiler.Report.Error (431, loc,
10031 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10036 TypeSpec nested = null;
10037 while (expr_type != null) {
10038 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10039 if (nested == null) {
10040 if (expr_type == tnew_expr) {
10041 Error_IdentifierNotFound (rc, expr_type);
10045 expr_type = tnew_expr;
10046 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10047 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10051 if (nested.IsAccessible (rc))
10055 // Keep looking after inaccessible candidate but only if
10056 // we are not in same context as the definition itself
10058 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10061 expr_type = expr_type.BaseType;
10066 if (HasTypeArguments) {
10067 texpr = new GenericTypeExpr (nested, targs, loc);
10069 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10071 texpr = new GenericOpenTypeExpr (nested, loc);
10073 } else if (expr_resolved is GenericOpenTypeExpr) {
10074 texpr = new GenericOpenTypeExpr (nested, loc);
10076 texpr = new TypeExpression (nested, loc);
10079 if (texpr.ResolveAsType (rc) == null)
10085 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10087 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10089 if (nested != null) {
10090 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10094 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10095 if (any_other_member != null) {
10096 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10100 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10101 Name, expr_type.GetSignatureForError ());
10104 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10106 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10109 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10111 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10112 ec.Report.SymbolRelatedToPreviousError (type);
10114 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10116 // a using directive or an assembly reference
10117 if (cand != null) {
10118 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10120 missing = "an assembly reference";
10123 ec.Report.Error (1061, loc,
10124 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10125 type.GetSignatureForError (), name, missing);
10129 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10132 public override string GetSignatureForError ()
10134 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10137 protected override void CloneTo (CloneContext clonectx, Expression t)
10139 MemberAccess target = (MemberAccess) t;
10141 target.expr = expr.Clone (clonectx);
10144 public override object Accept (StructuralVisitor visitor)
10146 return visitor.Visit (this);
10150 public class ConditionalMemberAccess : MemberAccess
10152 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10153 : base (expr, identifier, args, loc)
10157 public override bool HasConditionalAccess ()
10164 /// Implements checked expressions
10166 public class CheckedExpr : Expression {
10168 public Expression Expr;
10170 public CheckedExpr (Expression e, Location l)
10176 public override bool ContainsEmitWithAwait ()
10178 return Expr.ContainsEmitWithAwait ();
10181 public override Expression CreateExpressionTree (ResolveContext ec)
10183 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10184 return Expr.CreateExpressionTree (ec);
10187 protected override Expression DoResolve (ResolveContext ec)
10189 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10190 Expr = Expr.Resolve (ec);
10195 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10198 eclass = Expr.eclass;
10203 public override void Emit (EmitContext ec)
10205 using (ec.With (EmitContext.Options.CheckedScope, true))
10209 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10211 using (ec.With (EmitContext.Options.CheckedScope, true))
10212 Expr.EmitBranchable (ec, target, on_true);
10215 public override void FlowAnalysis (FlowAnalysisContext fc)
10217 Expr.FlowAnalysis (fc);
10220 public override SLE.Expression MakeExpression (BuilderContext ctx)
10222 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10223 return Expr.MakeExpression (ctx);
10227 protected override void CloneTo (CloneContext clonectx, Expression t)
10229 CheckedExpr target = (CheckedExpr) t;
10231 target.Expr = Expr.Clone (clonectx);
10234 public override object Accept (StructuralVisitor visitor)
10236 return visitor.Visit (this);
10241 /// Implements the unchecked expression
10243 public class UnCheckedExpr : Expression {
10245 public Expression Expr;
10247 public UnCheckedExpr (Expression e, Location l)
10253 public override bool ContainsEmitWithAwait ()
10255 return Expr.ContainsEmitWithAwait ();
10258 public override Expression CreateExpressionTree (ResolveContext ec)
10260 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10261 return Expr.CreateExpressionTree (ec);
10264 protected override Expression DoResolve (ResolveContext ec)
10266 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10267 Expr = Expr.Resolve (ec);
10272 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10275 eclass = Expr.eclass;
10280 public override void Emit (EmitContext ec)
10282 using (ec.With (EmitContext.Options.CheckedScope, false))
10286 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10288 using (ec.With (EmitContext.Options.CheckedScope, false))
10289 Expr.EmitBranchable (ec, target, on_true);
10292 public override void FlowAnalysis (FlowAnalysisContext fc)
10294 Expr.FlowAnalysis (fc);
10297 protected override void CloneTo (CloneContext clonectx, Expression t)
10299 UnCheckedExpr target = (UnCheckedExpr) t;
10301 target.Expr = Expr.Clone (clonectx);
10304 public override object Accept (StructuralVisitor visitor)
10306 return visitor.Visit (this);
10311 /// An Element Access expression.
10313 /// During semantic analysis these are transformed into
10314 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10316 public class ElementAccess : Expression
10318 public Arguments Arguments;
10319 public Expression Expr;
10320 bool conditional_access_receiver;
10322 public ElementAccess (Expression e, Arguments args, Location loc)
10326 this.Arguments = args;
10329 public bool ConditionalAccess { get; set; }
10331 public override Location StartLocation {
10333 return Expr.StartLocation;
10337 public override bool ContainsEmitWithAwait ()
10339 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10343 // We perform some simple tests, and then to "split" the emit and store
10344 // code we create an instance of a different class, and return that.
10346 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10348 if (conditionalAccessReceiver)
10349 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10351 Expr = Expr.Resolve (ec);
10353 if (conditionalAccessReceiver)
10354 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10361 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10362 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10366 if (type.IsArray) {
10367 var aa = new ArrayAccess (this, loc) {
10368 ConditionalAccess = ConditionalAccess,
10371 if (conditionalAccessReceiver)
10372 aa.SetConditionalAccessReceiver ();
10377 if (type.IsPointer)
10378 return Expr.MakePointerAccess (ec, type, Arguments);
10380 FieldExpr fe = Expr as FieldExpr;
10382 var ff = fe.Spec as FixedFieldSpec;
10384 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10388 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10389 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10390 var indexer = new IndexerExpr (indexers, type, this) {
10391 ConditionalAccess = ConditionalAccess
10394 if (conditionalAccessReceiver)
10395 indexer.SetConditionalAccessReceiver ();
10400 Error_CannotApplyIndexing (ec, type, loc);
10405 public override Expression CreateExpressionTree (ResolveContext ec)
10407 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10408 Expr.CreateExpressionTree (ec));
10410 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10413 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10415 if (type != InternalType.ErrorType) {
10416 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10417 type.GetSignatureForError ());
10421 public override bool HasConditionalAccess ()
10423 return ConditionalAccess || Expr.HasConditionalAccess ();
10426 void ResolveConditionalAccessReceiver (ResolveContext rc)
10428 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10429 conditional_access_receiver = true;
10433 protected override Expression DoResolve (ResolveContext rc)
10435 ResolveConditionalAccessReceiver (rc);
10437 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10441 return expr.Resolve (rc);
10444 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10446 var res = CreateAccessExpression (ec, false);
10450 return res.ResolveLValue (ec, rhs);
10453 public override void Emit (EmitContext ec)
10455 throw new Exception ("Should never be reached");
10458 public override void FlowAnalysis (FlowAnalysisContext fc)
10460 Expr.FlowAnalysis (fc);
10462 Arguments.FlowAnalysis (fc);
10465 public override string GetSignatureForError ()
10467 return Expr.GetSignatureForError ();
10470 protected override void CloneTo (CloneContext clonectx, Expression t)
10472 ElementAccess target = (ElementAccess) t;
10474 target.Expr = Expr.Clone (clonectx);
10475 if (Arguments != null)
10476 target.Arguments = Arguments.Clone (clonectx);
10479 public override object Accept (StructuralVisitor visitor)
10481 return visitor.Visit (this);
10486 /// Implements array access
10488 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10490 // Points to our "data" repository
10494 LocalTemporary temp;
10496 bool? has_await_args;
10497 bool conditional_access_receiver;
10499 public ArrayAccess (ElementAccess ea_data, Location l)
10505 public bool ConditionalAccess { get; set; }
10507 public void AddressOf (EmitContext ec, AddressOp mode)
10509 var ac = (ArrayContainer) ea.Expr.Type;
10511 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10512 LoadInstanceAndArguments (ec, false, true);
10515 LoadInstanceAndArguments (ec, false, false);
10517 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10518 ec.Emit (OpCodes.Readonly);
10520 ec.EmitArrayAddress (ac);
10523 public override Expression CreateExpressionTree (ResolveContext ec)
10525 if (ConditionalAccess)
10526 Error_NullShortCircuitInsideExpressionTree (ec);
10528 return ea.CreateExpressionTree (ec);
10531 public override bool ContainsEmitWithAwait ()
10533 return ea.ContainsEmitWithAwait ();
10536 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10538 if (HasConditionalAccess ())
10539 Error_NullPropagatingLValue (ec);
10541 return DoResolve (ec);
10544 protected override Expression DoResolve (ResolveContext ec)
10546 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10548 ea.Arguments.Resolve (ec, out dynamic);
10550 var ac = ea.Expr.Type as ArrayContainer;
10551 int rank = ea.Arguments.Count;
10552 if (ac.Rank != rank) {
10553 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10554 rank.ToString (), ac.Rank.ToString ());
10559 if (type.IsPointer) {
10560 if (ec.CurrentIterator != null) {
10561 UnsafeInsideIteratorError (ec, ea.Location);
10562 } else if (!ec.IsUnsafe) {
10563 UnsafeError (ec, ea.Location);
10567 if (conditional_access_receiver)
10568 type = LiftMemberType (ec, type);
10570 foreach (Argument a in ea.Arguments) {
10571 var na = a as NamedArgument;
10573 ElementAccess.Error_NamedArgument (na, ec.Report);
10575 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10578 eclass = ExprClass.Variable;
10583 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10585 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10588 public override void FlowAnalysis (FlowAnalysisContext fc)
10590 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10592 ea.FlowAnalysis (fc);
10594 if (conditional_access_receiver)
10595 fc.DefiniteAssignment = da;
10598 public override bool HasConditionalAccess ()
10600 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10604 // Load the array arguments into the stack.
10606 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10608 if (prepareAwait) {
10609 ea.Expr = ea.Expr.EmitToField (ec);
10611 var ie = new InstanceEmitter (ea.Expr, false);
10612 ie.Emit (ec, ConditionalAccess);
10614 if (duplicateArguments) {
10615 ec.Emit (OpCodes.Dup);
10617 var copy = new LocalTemporary (ea.Expr.Type);
10623 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10624 if (dup_args != null)
10625 ea.Arguments = dup_args;
10628 public void Emit (EmitContext ec, bool leave_copy)
10631 ec.EmitLoadFromPtr (type);
10633 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10634 LoadInstanceAndArguments (ec, false, true);
10637 if (conditional_access_receiver)
10638 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10640 var ac = (ArrayContainer) ea.Expr.Type;
10641 LoadInstanceAndArguments (ec, false, false);
10642 ec.EmitArrayLoad (ac);
10644 if (conditional_access_receiver)
10645 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10649 ec.Emit (OpCodes.Dup);
10650 temp = new LocalTemporary (this.type);
10655 public override void Emit (EmitContext ec)
10660 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10662 var ac = (ArrayContainer) ea.Expr.Type;
10663 TypeSpec t = source.Type;
10665 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10668 // When we are dealing with a struct, get the address of it to avoid value copy
10669 // Same cannot be done for reference type because array covariance and the
10670 // check in ldelema requires to specify the type of array element stored at the index
10672 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10673 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10675 if (has_await_args.Value) {
10676 if (source.ContainsEmitWithAwait ()) {
10677 source = source.EmitToField (ec);
10678 isCompound = false;
10682 LoadInstanceAndArguments (ec, isCompound, false);
10687 ec.EmitArrayAddress (ac);
10690 ec.Emit (OpCodes.Dup);
10694 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10696 if (has_await_args.Value) {
10697 if (source.ContainsEmitWithAwait ())
10698 source = source.EmitToField (ec);
10700 LoadInstanceAndArguments (ec, false, false);
10707 var lt = ea.Expr as LocalTemporary;
10713 ec.Emit (OpCodes.Dup);
10714 temp = new LocalTemporary (this.type);
10719 ec.EmitStoreFromPtr (t);
10721 ec.EmitArrayStore (ac);
10724 if (temp != null) {
10730 public override Expression EmitToField (EmitContext ec)
10733 // Have to be specialized for arrays to get access to
10734 // underlying element. Instead of another result copy we
10735 // need direct access to element
10739 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10741 ea.Expr = ea.Expr.EmitToField (ec);
10742 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10746 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10748 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10751 public override SLE.Expression MakeExpression (BuilderContext ctx)
10753 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10756 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10758 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10759 return Arguments.MakeExpression (ea.Arguments, ctx);
10763 public void SetConditionalAccessReceiver ()
10765 conditional_access_receiver = true;
10770 // Indexer access expression
10772 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10774 IList<MemberSpec> indexers;
10775 Arguments arguments;
10776 TypeSpec queried_type;
10778 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10779 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10783 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10786 this.indexers = indexers;
10787 this.queried_type = queriedType;
10788 this.InstanceExpression = instance;
10789 this.arguments = args;
10794 protected override Arguments Arguments {
10803 protected override TypeSpec DeclaringType {
10805 return best_candidate.DeclaringType;
10809 public override bool IsInstance {
10815 public override bool IsStatic {
10821 public override string KindName {
10822 get { return "indexer"; }
10825 public override string Name {
10833 public override bool ContainsEmitWithAwait ()
10835 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10838 public override Expression CreateExpressionTree (ResolveContext ec)
10840 if (ConditionalAccess) {
10841 Error_NullShortCircuitInsideExpressionTree (ec);
10844 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10845 InstanceExpression.CreateExpressionTree (ec),
10846 new TypeOfMethod (Getter, loc));
10848 return CreateExpressionFactoryCall (ec, "Call", args);
10851 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10853 LocalTemporary await_source_arg = null;
10856 emitting_compound_assignment = true;
10857 if (source is DynamicExpressionStatement) {
10862 emitting_compound_assignment = false;
10864 if (has_await_arguments) {
10865 await_source_arg = new LocalTemporary (Type);
10866 await_source_arg.Store (ec);
10868 arguments.Add (new Argument (await_source_arg));
10871 temp = await_source_arg;
10874 has_await_arguments = false;
10879 ec.Emit (OpCodes.Dup);
10880 temp = new LocalTemporary (Type);
10886 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10887 source = source.EmitToField (ec);
10889 temp = new LocalTemporary (Type);
10896 arguments.Add (new Argument (source));
10899 var call = new CallEmitter ();
10900 call.InstanceExpression = InstanceExpression;
10901 if (arguments == null)
10902 call.InstanceExpressionOnStack = true;
10904 call.Emit (ec, Setter, arguments, loc);
10906 if (temp != null) {
10909 } else if (leave_copy) {
10913 if (await_source_arg != null) {
10914 await_source_arg.Release (ec);
10918 public override void FlowAnalysis (FlowAnalysisContext fc)
10920 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10922 base.FlowAnalysis (fc);
10923 arguments.FlowAnalysis (fc);
10925 if (conditional_access_receiver)
10926 fc.DefiniteAssignment = da;
10929 public override string GetSignatureForError ()
10931 return best_candidate.GetSignatureForError ();
10934 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10937 throw new NotSupportedException ();
10939 var value = new[] { source.MakeExpression (ctx) };
10940 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10941 return SLE.Expression.Block (
10942 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10947 public override SLE.Expression MakeExpression (BuilderContext ctx)
10950 return base.MakeExpression (ctx);
10952 var args = Arguments.MakeExpression (arguments, ctx);
10953 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10957 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10959 if (best_candidate != null)
10962 eclass = ExprClass.IndexerAccess;
10965 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10966 arguments.Resolve (rc, out dynamic);
10969 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10972 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10973 res.BaseMembersProvider = this;
10974 res.InstanceQualifier = this;
10976 // TODO: Do I need 2 argument sets?
10977 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10978 if (best_candidate != null)
10979 type = res.BestCandidateReturnType;
10980 else if (!res.BestCandidateIsDynamic)
10985 // It has dynamic arguments
10988 Arguments args = new Arguments (arguments.Count + 1);
10990 rc.Report.Error (1972, loc,
10991 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10993 args.Add (new Argument (InstanceExpression));
10995 args.AddRange (arguments);
10997 best_candidate = null;
10998 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11002 // Try to avoid resolving left expression again
11004 if (right_side != null)
11005 ResolveInstanceExpression (rc, right_side);
11010 protected override void CloneTo (CloneContext clonectx, Expression t)
11012 IndexerExpr target = (IndexerExpr) t;
11014 if (arguments != null)
11015 target.arguments = arguments.Clone (clonectx);
11018 public void SetConditionalAccessReceiver ()
11020 conditional_access_receiver = true;
11023 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11025 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11028 #region IBaseMembersProvider Members
11030 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11032 var baseType = type.BaseType;
11033 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11035 if (members == null && !type.IsInterface) {
11036 var tps = queried_type as TypeParameterSpec;
11038 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11044 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11046 if (queried_type == member.DeclaringType)
11049 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11050 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11053 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11062 // A base access expression
11064 public class BaseThis : This
11066 public BaseThis (Location loc)
11071 public BaseThis (TypeSpec type, Location loc)
11075 eclass = ExprClass.Variable;
11080 public override string Name {
11088 public override Expression CreateExpressionTree (ResolveContext ec)
11090 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11091 return base.CreateExpressionTree (ec);
11094 public override void Emit (EmitContext ec)
11098 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11099 var context_type = ec.CurrentType;
11100 ec.Emit (OpCodes.Ldobj, context_type);
11101 ec.Emit (OpCodes.Box, context_type);
11105 protected override void Error_ThisNotAvailable (ResolveContext ec)
11108 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11110 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11114 public override void ResolveBase (ResolveContext ec)
11116 base.ResolveBase (ec);
11117 type = ec.CurrentType.BaseType;
11120 public override object Accept (StructuralVisitor visitor)
11122 return visitor.Visit (this);
11127 /// This class exists solely to pass the Type around and to be a dummy
11128 /// that can be passed to the conversion functions (this is used by
11129 /// foreach implementation to typecast the object return value from
11130 /// get_Current into the proper type. All code has been generated and
11131 /// we only care about the side effect conversions to be performed
11133 /// This is also now used as a placeholder where a no-action expression
11134 /// is needed (the `New' class).
11136 public class EmptyExpression : Expression
11138 sealed class OutAccessExpression : EmptyExpression
11140 public OutAccessExpression (TypeSpec t)
11145 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11147 rc.Report.Error (206, right_side.Location,
11148 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11154 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11155 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11156 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11157 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11158 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11159 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11160 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11161 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11163 public EmptyExpression (TypeSpec t)
11166 eclass = ExprClass.Value;
11167 loc = Location.Null;
11170 protected override void CloneTo (CloneContext clonectx, Expression target)
11174 public override bool ContainsEmitWithAwait ()
11179 public override Expression CreateExpressionTree (ResolveContext ec)
11181 throw new NotSupportedException ("ET");
11184 protected override Expression DoResolve (ResolveContext ec)
11189 public override void Emit (EmitContext ec)
11191 // nothing, as we only exist to not do anything.
11194 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11198 public override void EmitSideEffect (EmitContext ec)
11202 public override object Accept (StructuralVisitor visitor)
11204 return visitor.Visit (this);
11208 sealed class EmptyAwaitExpression : EmptyExpression
11210 public EmptyAwaitExpression (TypeSpec type)
11215 public override bool ContainsEmitWithAwait ()
11222 // Empty statement expression
11224 public sealed class EmptyExpressionStatement : ExpressionStatement
11226 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11228 private EmptyExpressionStatement ()
11230 loc = Location.Null;
11233 public override bool ContainsEmitWithAwait ()
11238 public override Expression CreateExpressionTree (ResolveContext ec)
11243 public override void EmitStatement (EmitContext ec)
11248 protected override Expression DoResolve (ResolveContext ec)
11250 eclass = ExprClass.Value;
11251 type = ec.BuiltinTypes.Object;
11255 public override void Emit (EmitContext ec)
11260 public override object Accept (StructuralVisitor visitor)
11262 return visitor.Visit (this);
11266 public class ErrorExpression : EmptyExpression
11268 public static readonly ErrorExpression Instance = new ErrorExpression ();
11270 private ErrorExpression ()
11271 : base (InternalType.ErrorType)
11275 public override Expression CreateExpressionTree (ResolveContext ec)
11280 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11285 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11289 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11293 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11297 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11301 public override object Accept (StructuralVisitor visitor)
11303 return visitor.Visit (this);
11307 public class UserCast : Expression {
11311 public UserCast (MethodSpec method, Expression source, Location l)
11313 if (source == null)
11314 throw new ArgumentNullException ("source");
11316 this.method = method;
11317 this.source = source;
11318 type = method.ReturnType;
11322 public Expression Source {
11331 public override bool ContainsEmitWithAwait ()
11333 return source.ContainsEmitWithAwait ();
11336 public override Expression CreateExpressionTree (ResolveContext ec)
11338 Arguments args = new Arguments (3);
11339 args.Add (new Argument (source.CreateExpressionTree (ec)));
11340 args.Add (new Argument (new TypeOf (type, loc)));
11341 args.Add (new Argument (new TypeOfMethod (method, loc)));
11342 return CreateExpressionFactoryCall (ec, "Convert", args);
11345 protected override Expression DoResolve (ResolveContext ec)
11347 method.CheckObsoleteness (ec, source.Location);
11349 eclass = ExprClass.Value;
11353 public override void Emit (EmitContext ec)
11356 ec.MarkCallEntry (loc);
11357 ec.Emit (OpCodes.Call, method);
11360 public override void FlowAnalysis (FlowAnalysisContext fc)
11362 source.FlowAnalysis (fc);
11365 public override string GetSignatureForError ()
11367 return TypeManager.CSharpSignature (method);
11370 public override SLE.Expression MakeExpression (BuilderContext ctx)
11373 return base.MakeExpression (ctx);
11375 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11381 // Holds additional type specifiers like ?, *, []
11383 public class ComposedTypeSpecifier
11385 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11387 public readonly int Dimension;
11388 public readonly Location Location;
11390 public ComposedTypeSpecifier (int specifier, Location loc)
11392 this.Dimension = specifier;
11393 this.Location = loc;
11397 public bool IsNullable {
11399 return Dimension == -1;
11403 public bool IsPointer {
11405 return Dimension == -2;
11409 public ComposedTypeSpecifier Next { get; set; }
11413 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11415 return new ComposedTypeSpecifier (dimension, loc);
11418 public static ComposedTypeSpecifier CreateNullable (Location loc)
11420 return new ComposedTypeSpecifier (-1, loc);
11423 public static ComposedTypeSpecifier CreatePointer (Location loc)
11425 return new ComposedTypeSpecifier (-2, loc);
11428 public string GetSignatureForError ()
11433 ArrayContainer.GetPostfixSignature (Dimension);
11435 return Next != null ? s + Next.GetSignatureForError () : s;
11440 // This class is used to "construct" the type during a typecast
11441 // operation. Since the Type.GetType class in .NET can parse
11442 // the type specification, we just use this to construct the type
11443 // one bit at a time.
11445 public class ComposedCast : TypeExpr {
11446 FullNamedExpression left;
11447 ComposedTypeSpecifier spec;
11449 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11452 throw new ArgumentNullException ("spec");
11456 this.loc = left.Location;
11459 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11461 type = left.ResolveAsType (ec);
11465 eclass = ExprClass.Type;
11467 var single_spec = spec;
11469 if (single_spec.IsNullable) {
11470 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11474 single_spec = single_spec.Next;
11475 } else if (single_spec.IsPointer) {
11477 // Declared fields cannot have unmanaged check done before all types are defined
11479 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11482 var rc = ec as ResolveContext;
11483 if (rc?.CurrentIterator != null) {
11484 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11485 } else if (!ec.IsUnsafe) {
11486 UnsafeError (ec.Module.Compiler.Report, loc);
11490 type = PointerContainer.MakeType (ec.Module, type);
11491 single_spec = single_spec.Next;
11492 } while (single_spec != null && single_spec.IsPointer);
11495 if (single_spec != null && single_spec.Dimension > 0) {
11496 if (type.IsSpecialRuntimeType) {
11497 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11498 } else if (type.IsStatic) {
11499 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11500 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11501 type.GetSignatureForError ());
11503 MakeArray (ec.Module, single_spec);
11510 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11512 if (spec.Next != null)
11513 MakeArray (module, spec.Next);
11515 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11518 public override string GetSignatureForError ()
11520 return left.GetSignatureForError () + spec.GetSignatureForError ();
11523 public override object Accept (StructuralVisitor visitor)
11525 return visitor.Visit (this);
11529 class FixedBufferPtr : Expression
11531 readonly Expression array;
11533 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11535 this.type = array_type;
11536 this.array = array;
11540 public override bool ContainsEmitWithAwait ()
11542 throw new NotImplementedException ();
11545 public override Expression CreateExpressionTree (ResolveContext ec)
11547 Error_PointerInsideExpressionTree (ec);
11551 public override void Emit(EmitContext ec)
11556 protected override Expression DoResolve (ResolveContext ec)
11558 type = PointerContainer.MakeType (ec.Module, type);
11559 eclass = ExprClass.Value;
11566 // This class is used to represent the address of an array, used
11567 // only by the Fixed statement, this generates "&a [0]" construct
11568 // for fixed (char *pa = a)
11570 class ArrayPtr : FixedBufferPtr
11572 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11573 base (array, array_type, l)
11577 public override void Emit (EmitContext ec)
11582 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11587 // Encapsulates a conversion rules required for array indexes
11589 public class ArrayIndexCast : TypeCast
11591 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11592 : base (expr, returnType)
11594 if (expr.Type == returnType) // int -> int
11595 throw new ArgumentException ("unnecessary array index conversion");
11598 public override Expression CreateExpressionTree (ResolveContext ec)
11600 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11601 return base.CreateExpressionTree (ec);
11605 public override void Emit (EmitContext ec)
11609 switch (child.Type.BuiltinType) {
11610 case BuiltinTypeSpec.Type.UInt:
11611 ec.Emit (OpCodes.Conv_U);
11613 case BuiltinTypeSpec.Type.Long:
11614 ec.Emit (OpCodes.Conv_Ovf_I);
11616 case BuiltinTypeSpec.Type.ULong:
11617 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11620 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11626 // Implements the `stackalloc' keyword
11628 public class StackAlloc : Expression {
11633 public StackAlloc (Expression type, Expression count, Location l)
11636 this.count = count;
11640 public Expression TypeExpression {
11646 public Expression CountExpression {
11652 public override bool ContainsEmitWithAwait ()
11657 public override Expression CreateExpressionTree (ResolveContext ec)
11659 throw new NotSupportedException ("ET");
11662 protected override Expression DoResolve (ResolveContext ec)
11664 count = count.Resolve (ec);
11668 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11669 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11674 Constant c = count as Constant;
11675 if (c != null && c.IsNegative) {
11676 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11679 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11680 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11683 otype = texpr.ResolveAsType (ec);
11687 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11690 type = PointerContainer.MakeType (ec.Module, otype);
11691 eclass = ExprClass.Value;
11696 public override void Emit (EmitContext ec)
11698 int size = BuiltinTypeSpec.GetSize (otype);
11703 ec.Emit (OpCodes.Sizeof, otype);
11707 ec.Emit (OpCodes.Mul_Ovf_Un);
11708 ec.Emit (OpCodes.Localloc);
11711 protected override void CloneTo (CloneContext clonectx, Expression t)
11713 StackAlloc target = (StackAlloc) t;
11714 target.count = count.Clone (clonectx);
11715 target.texpr = texpr.Clone (clonectx);
11718 public override object Accept (StructuralVisitor visitor)
11720 return visitor.Visit (this);
11725 // An object initializer expression
11727 public class ElementInitializer : Assign
11729 public readonly string Name;
11731 public ElementInitializer (string name, Expression initializer, Location loc)
11732 : base (null, initializer, loc)
11737 public bool IsDictionaryInitializer {
11739 return Name == null;
11743 protected override void CloneTo (CloneContext clonectx, Expression t)
11745 ElementInitializer target = (ElementInitializer) t;
11746 target.source = source.Clone (clonectx);
11749 public override Expression CreateExpressionTree (ResolveContext ec)
11751 Arguments args = new Arguments (2);
11752 FieldExpr fe = target as FieldExpr;
11754 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11756 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11759 Expression arg_expr;
11760 var cinit = source as CollectionOrObjectInitializers;
11761 if (cinit == null) {
11763 arg_expr = source.CreateExpressionTree (ec);
11765 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11766 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11769 args.Add (new Argument (arg_expr));
11770 return CreateExpressionFactoryCall (ec, mname, args);
11773 protected override Expression DoResolve (ResolveContext ec)
11775 if (source == null)
11776 return EmptyExpressionStatement.Instance;
11778 if (!ResolveElement (ec))
11781 if (source is CollectionOrObjectInitializers) {
11782 target = target.Resolve (ec);
11783 if (target == null)
11786 Expression previous = ec.CurrentInitializerVariable;
11787 ec.CurrentInitializerVariable = target;
11788 source = source.Resolve (ec);
11789 ec.CurrentInitializerVariable = previous;
11790 if (source == null)
11793 eclass = source.eclass;
11794 type = source.Type;
11799 return base.DoResolve (ec);
11802 public override void EmitStatement (EmitContext ec)
11804 if (source is CollectionOrObjectInitializers)
11807 base.EmitStatement (ec);
11810 protected virtual bool ResolveElement (ResolveContext rc)
11812 var t = rc.CurrentInitializerVariable.Type;
11813 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11814 Arguments args = new Arguments (1);
11815 args.Add (new Argument (rc.CurrentInitializerVariable));
11816 target = new DynamicMemberBinder (Name, args, loc);
11818 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11819 if (member == null) {
11820 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11822 if (member != null) {
11823 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11824 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11829 if (member == null) {
11830 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11834 var me = member as MemberExpr;
11835 if (me is EventExpr) {
11836 me = me.ResolveMemberAccess (rc, null, null);
11837 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11838 rc.Report.Error (1913, loc,
11839 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11840 member.GetSignatureForError ());
11846 rc.Report.Error (1914, loc,
11847 "Static field or property `{0}' cannot be assigned in an object initializer",
11848 me.GetSignatureForError ());
11852 me.InstanceExpression = rc.CurrentInitializerVariable;
11860 // A collection initializer expression
11862 class CollectionElementInitializer : Invocation
11864 public class ElementInitializerArgument : Argument
11866 public ElementInitializerArgument (Expression e)
11872 sealed class AddMemberAccess : MemberAccess
11874 public AddMemberAccess (Expression expr, Location loc)
11875 : base (expr, "Add", loc)
11879 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11881 if (TypeManager.HasElementType (type))
11884 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11888 public CollectionElementInitializer (Expression argument)
11889 : base (null, new Arguments (1))
11891 base.arguments.Add (new ElementInitializerArgument (argument));
11892 this.loc = argument.Location;
11895 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11896 : base (null, new Arguments (arguments.Count))
11898 foreach (Expression e in arguments)
11899 base.arguments.Add (new ElementInitializerArgument (e));
11904 public CollectionElementInitializer (Location loc)
11905 : base (null, null)
11910 public override Expression CreateExpressionTree (ResolveContext ec)
11912 Arguments args = new Arguments (2);
11913 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11915 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11916 foreach (Argument a in arguments) {
11917 if (a.ArgType == Argument.AType.ExtensionType) {
11918 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11921 expr_initializers.Add (a.CreateExpressionTree (ec));
11924 args.Add (new Argument (new ArrayCreation (
11925 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11926 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11929 protected override void CloneTo (CloneContext clonectx, Expression t)
11931 CollectionElementInitializer target = (CollectionElementInitializer) t;
11932 if (arguments != null)
11933 target.arguments = arguments.Clone (clonectx);
11936 protected override Expression DoResolve (ResolveContext ec)
11938 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11940 return base.DoResolve (ec);
11944 class DictionaryElementInitializer : ElementInitializer
11946 readonly Arguments args;
11948 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11949 : base (null, initializer, loc)
11951 this.args = arguments;
11954 public override Expression CreateExpressionTree (ResolveContext ec)
11956 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11960 protected override bool ResolveElement (ResolveContext rc)
11962 var init = rc.CurrentInitializerVariable;
11963 var type = init.Type;
11965 if (type.IsArray) {
11966 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11970 if (type.IsPointer) {
11971 target = init.MakePointerAccess (rc, type, args);
11975 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11976 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11977 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11981 target = new IndexerExpr (indexers, type, init, args, loc);
11987 // A block of object or collection initializers
11989 public class CollectionOrObjectInitializers : ExpressionStatement
11991 IList<Expression> initializers;
11992 bool is_collection_initialization;
11994 public CollectionOrObjectInitializers (Location loc)
11995 : this (new Expression[0], loc)
11999 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12001 this.initializers = initializers;
12005 public IList<Expression> Initializers {
12007 return initializers;
12011 public bool IsEmpty {
12013 return initializers.Count == 0;
12017 public bool IsCollectionInitializer {
12019 return is_collection_initialization;
12023 protected override void CloneTo (CloneContext clonectx, Expression target)
12025 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12027 t.initializers = new List<Expression> (initializers.Count);
12028 foreach (var e in initializers)
12029 t.initializers.Add (e.Clone (clonectx));
12032 public override bool ContainsEmitWithAwait ()
12034 foreach (var e in initializers) {
12035 if (e.ContainsEmitWithAwait ())
12042 public override Expression CreateExpressionTree (ResolveContext ec)
12044 return CreateExpressionTree (ec, false);
12047 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12049 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12050 foreach (Expression e in initializers) {
12051 Expression expr = e.CreateExpressionTree (ec);
12053 expr_initializers.Add (expr);
12057 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12059 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12062 protected override Expression DoResolve (ResolveContext ec)
12064 List<string> element_names = null;
12065 for (int i = 0; i < initializers.Count; ++i) {
12066 Expression initializer = initializers [i];
12067 ElementInitializer element_initializer = initializer as ElementInitializer;
12070 if (element_initializer != null) {
12071 element_names = new List<string> (initializers.Count);
12072 if (!element_initializer.IsDictionaryInitializer)
12073 element_names.Add (element_initializer.Name);
12074 } else if (initializer is CompletingExpression) {
12075 initializer.Resolve (ec);
12076 throw new InternalErrorException ("This line should never be reached");
12078 var t = ec.CurrentInitializerVariable.Type;
12079 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12080 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12081 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12082 "object initializer because type `{1}' does not implement `{2}' interface",
12083 ec.CurrentInitializerVariable.GetSignatureForError (),
12084 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12085 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12088 is_collection_initialization = true;
12091 if (is_collection_initialization != (element_initializer == null)) {
12092 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12093 is_collection_initialization ? "collection initializer" : "object initializer");
12097 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12098 if (element_names.Contains (element_initializer.Name)) {
12099 ec.Report.Error (1912, element_initializer.Location,
12100 "An object initializer includes more than one member `{0}' initialization",
12101 element_initializer.Name);
12103 element_names.Add (element_initializer.Name);
12108 Expression e = initializer.Resolve (ec);
12109 if (e == EmptyExpressionStatement.Instance)
12110 initializers.RemoveAt (i--);
12112 initializers [i] = e;
12115 type = ec.CurrentInitializerVariable.Type;
12116 if (is_collection_initialization) {
12117 if (TypeManager.HasElementType (type)) {
12118 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12119 type.GetSignatureForError ());
12123 eclass = ExprClass.Variable;
12127 public override void Emit (EmitContext ec)
12129 EmitStatement (ec);
12132 public override void EmitStatement (EmitContext ec)
12134 foreach (ExpressionStatement e in initializers) {
12135 // TODO: need location region
12136 ec.Mark (e.Location);
12137 e.EmitStatement (ec);
12141 public override void FlowAnalysis (FlowAnalysisContext fc)
12143 foreach (var initializer in initializers) {
12144 if (initializer != null)
12145 initializer.FlowAnalysis (fc);
12151 // New expression with element/object initializers
12153 public class NewInitialize : New
12156 // This class serves as a proxy for variable initializer target instances.
12157 // A real variable is assigned later when we resolve left side of an
12160 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12162 NewInitialize new_instance;
12164 public InitializerTargetExpression (NewInitialize newInstance)
12166 this.type = newInstance.type;
12167 this.loc = newInstance.loc;
12168 this.eclass = newInstance.eclass;
12169 this.new_instance = newInstance;
12172 public override bool ContainsEmitWithAwait ()
12177 public override Expression CreateExpressionTree (ResolveContext ec)
12179 // Should not be reached
12180 throw new NotSupportedException ("ET");
12183 protected override Expression DoResolve (ResolveContext ec)
12188 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12193 public override void Emit (EmitContext ec)
12195 Expression e = (Expression) new_instance.instance;
12199 public override Expression EmitToField (EmitContext ec)
12201 return (Expression) new_instance.instance;
12204 #region IMemoryLocation Members
12206 public void AddressOf (EmitContext ec, AddressOp mode)
12208 new_instance.instance.AddressOf (ec, mode);
12214 CollectionOrObjectInitializers initializers;
12215 IMemoryLocation instance;
12216 DynamicExpressionStatement dynamic;
12218 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12219 : base (requested_type, arguments, l)
12221 this.initializers = initializers;
12224 public CollectionOrObjectInitializers Initializers {
12226 return initializers;
12230 protected override void CloneTo (CloneContext clonectx, Expression t)
12232 base.CloneTo (clonectx, t);
12234 NewInitialize target = (NewInitialize) t;
12235 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12238 public override bool ContainsEmitWithAwait ()
12240 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12243 public override Expression CreateExpressionTree (ResolveContext ec)
12245 Arguments args = new Arguments (2);
12246 args.Add (new Argument (base.CreateExpressionTree (ec)));
12247 if (!initializers.IsEmpty)
12248 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12250 return CreateExpressionFactoryCall (ec,
12251 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12255 protected override Expression DoResolve (ResolveContext rc)
12257 Expression e = base.DoResolve (rc);
12261 if (type.IsDelegate) {
12262 rc.Report.Error (1958, Initializers.Location,
12263 "Object and collection initializers cannot be used to instantiate a delegate");
12266 Expression previous = rc.CurrentInitializerVariable;
12267 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12268 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12269 initializers.Resolve (rc);
12271 rc.CurrentInitializerVariable = previous;
12273 dynamic = e as DynamicExpressionStatement;
12274 if (dynamic != null)
12280 public override void Emit (EmitContext ec)
12282 if (!CanEmitOptimizedLocalTarget (ec)) {
12283 var fe = ec.GetTemporaryField (type);
12285 if (!Emit (ec, fe))
12294 public override bool Emit (EmitContext ec, IMemoryLocation target)
12297 // Expression is initialized into temporary target then moved
12298 // to real one for atomicity
12300 IMemoryLocation temp_target = target;
12302 LocalTemporary temp = null;
12303 bool by_ref = false;
12304 if (!initializers.IsEmpty) {
12305 temp_target = target as LocalTemporary;
12306 if (temp_target == null)
12307 temp_target = target as StackFieldExpr;
12309 if (temp_target == null) {
12310 var vr = target as VariableReference;
12311 if (vr != null && vr.IsRef) {
12317 if (temp_target == null)
12318 temp_target = temp = new LocalTemporary (type);
12321 bool left_on_stack;
12322 if (dynamic != null) {
12324 left_on_stack = true;
12326 left_on_stack = base.Emit (ec, temp_target);
12329 if (initializers.IsEmpty)
12330 return left_on_stack;
12332 StackFieldExpr sf = null;
12334 // Move a new instance (reference-type) to local temporary variable
12335 if (left_on_stack) {
12337 temp_target = temp = new LocalTemporary (type);
12343 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12345 throw new NotImplementedException ();
12347 sf = ec.GetTemporaryField (type);
12348 sf.AutomaticallyReuse = false;
12349 sf.EmitAssign (ec, temp, false, false);
12352 left_on_stack = false;
12356 instance = temp_target;
12358 initializers.Emit (ec);
12360 ((Expression)temp_target).Emit (ec);
12366 sf.PrepareCleanup (ec);
12371 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12373 return !(method == null && TypeSpec.IsValueType (type) &&
12374 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12375 initializers.ContainsEmitWithAwait ());
12378 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12380 instance = base.EmitAddressOf (ec, Mode);
12382 if (!initializers.IsEmpty)
12383 initializers.Emit (ec);
12388 public override void FlowAnalysis (FlowAnalysisContext fc)
12390 base.FlowAnalysis (fc);
12391 initializers.FlowAnalysis (fc);
12394 public override object Accept (StructuralVisitor visitor)
12396 return visitor.Visit (this);
12400 public class NewAnonymousType : New
12402 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12404 List<AnonymousTypeParameter> parameters;
12405 readonly TypeContainer parent;
12406 AnonymousTypeClass anonymous_type;
12408 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12409 : base (null, null, loc)
12411 this.parameters = parameters;
12412 this.parent = parent;
12415 public List<AnonymousTypeParameter> Parameters {
12417 return this.parameters;
12421 protected override void CloneTo (CloneContext clonectx, Expression target)
12423 if (parameters == null)
12426 NewAnonymousType t = (NewAnonymousType) target;
12427 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12428 foreach (AnonymousTypeParameter atp in parameters)
12429 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12432 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12434 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12438 type = AnonymousTypeClass.Create (parent, parameters, loc);
12442 int errors = ec.Report.Errors;
12443 type.CreateContainer ();
12444 type.DefineContainer ();
12445 type.ExpandBaseInterfaces ();
12447 if ((ec.Report.Errors - errors) == 0) {
12448 parent.Module.AddAnonymousType (type);
12449 type.PrepareEmit ();
12455 public override Expression CreateExpressionTree (ResolveContext ec)
12457 if (parameters == null)
12458 return base.CreateExpressionTree (ec);
12460 var init = new ArrayInitializer (parameters.Count, loc);
12461 foreach (var m in anonymous_type.Members) {
12462 var p = m as Property;
12464 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12467 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12468 foreach (Argument a in arguments)
12469 ctor_args.Add (a.CreateExpressionTree (ec));
12471 Arguments args = new Arguments (3);
12472 args.Add (new Argument (new TypeOfMethod (method, loc)));
12473 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12474 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12476 return CreateExpressionFactoryCall (ec, "New", args);
12479 protected override Expression DoResolve (ResolveContext ec)
12481 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12482 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12486 if (parameters == null) {
12487 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12488 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12489 return base.DoResolve (ec);
12492 bool error = false;
12493 arguments = new Arguments (parameters.Count);
12494 var t_args = new TypeSpec [parameters.Count];
12495 for (int i = 0; i < parameters.Count; ++i) {
12496 Expression e = parameters [i].Resolve (ec);
12502 arguments.Add (new Argument (e));
12503 t_args [i] = e.Type;
12509 anonymous_type = CreateAnonymousType (ec, parameters);
12510 if (anonymous_type == null)
12513 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12514 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12515 eclass = ExprClass.Value;
12519 public override object Accept (StructuralVisitor visitor)
12521 return visitor.Visit (this);
12525 public class AnonymousTypeParameter : ShimExpression
12527 public readonly string Name;
12529 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12530 : base (initializer)
12536 public AnonymousTypeParameter (Parameter parameter)
12537 : base (new SimpleName (parameter.Name, parameter.Location))
12539 this.Name = parameter.Name;
12540 this.loc = parameter.Location;
12543 public override bool Equals (object o)
12545 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12546 return other != null && Name == other.Name;
12549 public override int GetHashCode ()
12551 return Name.GetHashCode ();
12554 protected override Expression DoResolve (ResolveContext ec)
12556 Expression e = expr.Resolve (ec);
12560 if (e.eclass == ExprClass.MethodGroup) {
12561 Error_InvalidInitializer (ec, e.ExprClassName);
12566 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12567 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12574 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12576 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12577 Name, initializer);
12581 public class CatchFilterExpression : BooleanExpression
12583 public CatchFilterExpression (Expression expr, Location loc)
12590 public class InterpolatedString : Expression
12592 readonly StringLiteral start, end;
12593 List<Expression> interpolations;
12594 Arguments arguments;
12596 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12598 this.start = start;
12600 this.interpolations = interpolations;
12601 loc = start.Location;
12604 protected override void CloneTo (CloneContext clonectx, Expression t)
12606 InterpolatedString target = (InterpolatedString) t;
12608 if (interpolations != null) {
12609 target.interpolations = new List<Expression> ();
12610 foreach (var interpolation in interpolations) {
12611 target.interpolations.Add (interpolation.Clone (clonectx));
12616 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12618 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12619 if (factory == null)
12622 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12623 var res = new Invocation (ma, arguments).Resolve (rc);
12624 if (res != null && res.Type != type)
12625 res = Convert.ExplicitConversion (rc, res, type, loc);
12630 public override bool ContainsEmitWithAwait ()
12632 if (interpolations == null)
12635 foreach (var expr in interpolations) {
12636 if (expr.ContainsEmitWithAwait ())
12643 public override Expression CreateExpressionTree (ResolveContext rc)
12645 var best = ResolveBestFormatOverload (rc);
12649 Expression instance = new NullLiteral (loc);
12650 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12651 return CreateExpressionFactoryCall (rc, "Call", args);
12654 protected override Expression DoResolve (ResolveContext rc)
12658 if (interpolations == null) {
12660 arguments = new Arguments (1);
12662 arguments = new Arguments (interpolations.Count);
12664 var sb = new StringBuilder (start.Value);
12665 for (int i = 0; i < interpolations.Count; ++i) {
12667 sb.Append ('{').Append (i / 2);
12668 var isi = (InterpolatedStringInsert)interpolations [i];
12669 if (isi.Alignment != null) {
12671 var value = isi.ResolveAligment (rc);
12673 sb.Append (value.Value);
12676 if (isi.Format != null) {
12678 sb.Append (isi.Format);
12682 arguments.Add (new Argument (isi.Resolve (rc)));
12684 sb.Append (((StringLiteral)interpolations [i]).Value);
12688 sb.Append (end.Value);
12689 str = sb.ToString ();
12692 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12694 eclass = ExprClass.Value;
12695 type = rc.BuiltinTypes.String;
12699 public override void Emit (EmitContext ec)
12701 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12702 if (interpolations == null) {
12703 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12704 if (str != start.Value)
12705 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12712 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12716 var ca = new CallEmitter ();
12717 ca.Emit (ec, best, arguments, loc);
12720 public override void FlowAnalysis (FlowAnalysisContext fc)
12722 if (interpolations != null) {
12723 foreach (var expr in interpolations) {
12724 expr.FlowAnalysis (fc);
12729 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12731 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12732 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12733 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12737 public class InterpolatedStringInsert : CompositeExpression
12739 public InterpolatedStringInsert (Expression expr)
12744 public Expression Alignment { get; set; }
12745 public string Format { get; set; }
12747 protected override void CloneTo (CloneContext clonectx, Expression t)
12749 var target = (InterpolatedStringInsert)t;
12750 target.expr = expr.Clone (clonectx);
12751 if (Alignment != null)
12752 target.Alignment = Alignment.Clone (clonectx);
12755 protected override Expression DoResolve (ResolveContext rc)
12757 var expr = base.DoResolve (rc);
12762 // For better error reporting, assumes the built-in implementation uses object
12765 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12768 public override void FlowAnalysis (FlowAnalysisContext fc)
12770 Child.FlowAnalysis (fc);
12773 public int? ResolveAligment (ResolveContext rc)
12775 var c = Alignment.ResolveLabelConstant (rc);
12779 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12783 var value = (int) c.GetValueAsLong ();
12784 if (value > 32767 || value < -32767) {
12785 rc.Report.Warning (8094, 1, Alignment.Location,
12786 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12793 class ThrowExpression : ExpressionStatement
12797 public ThrowExpression (Expression expr, Location loc)
12803 protected override void CloneTo (CloneContext clonectx, Expression t)
12805 var target = (ThrowExpression)t;
12806 target.expr = expr.Clone (clonectx);
12809 public override bool ContainsEmitWithAwait ()
12811 return expr.ContainsEmitWithAwait ();
12814 public override Expression CreateExpressionTree (ResolveContext rc)
12816 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12820 protected override Expression DoResolve (ResolveContext rc)
12822 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12827 expr = Throw.ConvertType (rc, expr);
12829 eclass = ExprClass.Value;
12830 type = InternalType.ThrowExpr;
12834 public override void Emit (EmitContext ec)
12836 EmitStatement (ec);
12839 public override void EmitStatement (EmitContext ec)
12843 ec.Emit (OpCodes.Throw);
12846 public override void FlowAnalysis (FlowAnalysisContext fc)
12848 expr.FlowAnalysis (fc);
12851 public override Reachability MarkReachable (Reachability rc)
12853 return Reachability.CreateUnreachable ();