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 FlowAnalysis (FlowAnalysisContext fc)
1495 expr.FlowAnalysis (fc);
1498 public override bool HasConditionalAccess ()
1500 return expr.HasConditionalAccess ();
1503 protected abstract string OperatorName { get; }
1505 protected override void CloneTo (CloneContext clonectx, Expression t)
1507 Probe target = (Probe) t;
1509 target.expr = expr.Clone (clonectx);
1510 target.ProbeType = ProbeType.Clone (clonectx);
1516 /// Implementation of the `is' operator.
1518 public class Is : Probe
1520 Nullable.Unwrap expr_unwrap;
1521 MethodSpec number_mg;
1522 Arguments number_args;
1524 public Is (Expression expr, Expression probe_type, Location l)
1525 : base (expr, probe_type, l)
1529 protected override string OperatorName {
1530 get { return "is"; }
1533 public LocalVariable Variable { get; set; }
1535 public override Expression CreateExpressionTree (ResolveContext ec)
1537 if (Variable != null)
1538 throw new NotSupportedException ();
1540 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1541 expr.CreateExpressionTree (ec),
1542 new TypeOf (probe_type_expr, loc));
1544 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1547 Expression CreateConstantResult (ResolveContext rc, bool result)
1550 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1551 probe_type_expr.GetSignatureForError ());
1553 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1554 probe_type_expr.GetSignatureForError ());
1556 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1557 return expr.IsSideEffectFree ?
1558 ReducedExpression.Create (c, this) :
1559 new SideEffectConstant (c, this, loc);
1562 public override void Emit (EmitContext ec)
1564 if (probe_type_expr == null) {
1565 if (ProbeType is WildcardPattern) {
1566 expr.EmitSideEffect (ec);
1567 ProbeType.Emit (ec);
1569 EmitPatternMatch (ec);
1576 if (expr_unwrap == null) {
1578 ec.Emit (OpCodes.Cgt_Un);
1582 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1584 if (probe_type_expr == null) {
1585 EmitPatternMatch (ec);
1590 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1593 void EmitPatternMatch (EmitContext ec)
1595 var no_match = ec.DefineLabel ();
1596 var end = ec.DefineLabel ();
1598 if (expr_unwrap != null) {
1599 expr_unwrap.EmitCheck (ec);
1601 if (ProbeType.IsNull) {
1603 ec.Emit (OpCodes.Ceq);
1607 ec.Emit (OpCodes.Brfalse_S, no_match);
1608 expr_unwrap.Emit (ec);
1609 ProbeType.Emit (ec);
1610 ec.Emit (OpCodes.Ceq);
1611 ec.Emit (OpCodes.Br_S, end);
1612 ec.MarkLabel (no_match);
1618 if (number_args != null && number_args.Count == 3) {
1619 var ce = new CallEmitter ();
1620 ce.Emit (ec, number_mg, number_args, loc);
1624 var probe_type = ProbeType.Type;
1627 ec.Emit (OpCodes.Isinst, probe_type);
1628 ec.Emit (OpCodes.Dup);
1629 ec.Emit (OpCodes.Brfalse, no_match);
1631 bool complex_pattern = ProbeType is ComplexPatternExpression;
1632 Label prev = ec.RecursivePatternLabel;
1633 if (complex_pattern)
1634 ec.RecursivePatternLabel = ec.DefineLabel ();
1636 if (number_mg != null) {
1637 var ce = new CallEmitter ();
1638 ce.Emit (ec, number_mg, number_args, loc);
1640 if (TypeSpec.IsValueType (probe_type))
1641 ec.Emit (OpCodes.Unbox_Any, probe_type);
1643 ProbeType.Emit (ec);
1644 if (complex_pattern) {
1647 ec.Emit (OpCodes.Ceq);
1650 ec.Emit (OpCodes.Br_S, end);
1651 ec.MarkLabel (no_match);
1653 ec.Emit (OpCodes.Pop);
1655 if (complex_pattern)
1656 ec.MarkLabel (ec.RecursivePatternLabel);
1658 ec.RecursivePatternLabel = prev;
1664 void EmitLoad (EmitContext ec)
1666 Label no_value_label = new Label ();
1668 if (expr_unwrap != null) {
1669 expr_unwrap.EmitCheck (ec);
1671 if (Variable == null)
1674 ec.Emit (OpCodes.Dup);
1675 no_value_label = ec.DefineLabel ();
1676 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1677 expr_unwrap.Emit (ec);
1681 // Only to make verifier happy
1682 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1683 ec.Emit (OpCodes.Box, expr.Type);
1685 ec.Emit (OpCodes.Isinst, probe_type_expr);
1688 if (Variable != null) {
1689 bool value_on_stack;
1690 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1691 ec.Emit (OpCodes.Dup);
1692 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1693 value_on_stack = true;
1695 value_on_stack = false;
1698 Variable.CreateBuilder (ec);
1699 Variable.EmitAssign (ec);
1701 if (expr_unwrap != null) {
1702 ec.MarkLabel (no_value_label);
1703 } else if (!value_on_stack) {
1709 protected override Expression DoResolve (ResolveContext rc)
1711 if (ResolveCommon (rc) == null)
1714 type = rc.BuiltinTypes.Bool;
1715 eclass = ExprClass.Value;
1717 if (probe_type_expr == null)
1718 return ResolveMatchingExpression (rc);
1720 var res = ResolveResultExpression (rc);
1721 if (Variable != null) {
1722 if (res is Constant)
1723 throw new NotImplementedException ("constant in type pattern matching");
1725 Variable.Type = probe_type_expr;
1726 var bc = rc as BlockContext;
1728 Variable.PrepareAssignmentAnalysis (bc);
1734 public override void FlowAnalysis (FlowAnalysisContext fc)
1736 base.FlowAnalysis (fc);
1738 if (Variable != null)
1739 fc.SetVariableAssigned (Variable.VariableInfo, true);
1742 protected override void ResolveProbeType (ResolveContext rc)
1744 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1745 if (ProbeType is PatternExpression) {
1746 ProbeType.Resolve (rc);
1751 // Have to use session recording because we don't have reliable type probing
1752 // mechanism (similar issue as in attributes resolving)
1754 // TODO: This is still wrong because ResolveAsType can be destructive
1756 var type_printer = new SessionReportPrinter ();
1757 var prev_recorder = rc.Report.SetPrinter (type_printer);
1759 probe_type_expr = ProbeType.ResolveAsType (rc);
1760 type_printer.EndSession ();
1762 if (probe_type_expr != null) {
1763 type_printer.Merge (rc.Report.Printer);
1764 rc.Report.SetPrinter (prev_recorder);
1768 var vexpr = ProbeType as VarExpr;
1769 if (vexpr != null && vexpr.InferType (rc, expr)) {
1770 probe_type_expr = vexpr.Type;
1771 rc.Report.SetPrinter (prev_recorder);
1775 var expr_printer = new SessionReportPrinter ();
1776 rc.Report.SetPrinter (expr_printer);
1777 ProbeType = ProbeType.Resolve (rc);
1778 expr_printer.EndSession ();
1780 if (ProbeType != null) {
1781 expr_printer.Merge (rc.Report.Printer);
1783 type_printer.Merge (rc.Report.Printer);
1786 rc.Report.SetPrinter (prev_recorder);
1790 base.ResolveProbeType (rc);
1793 Expression ResolveMatchingExpression (ResolveContext rc)
1795 var mc = ProbeType as Constant;
1797 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1798 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1803 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1805 var c = Expr as Constant;
1807 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1812 if (Expr.Type.IsNullableType) {
1813 expr_unwrap = new Nullable.Unwrap (Expr);
1814 expr_unwrap.Resolve (rc);
1815 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1816 } else if (ProbeType.Type == Expr.Type) {
1817 // TODO: Better error handling
1818 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1819 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1820 var helper = rc.Module.CreatePatterMatchingHelper ();
1821 number_mg = helper.NumberMatcher.Spec;
1824 // There are actually 3 arguments but the first one is already on the stack
1826 number_args = new Arguments (3);
1827 if (!ProbeType.Type.IsEnum)
1828 number_args.Add (new Argument (Expr));
1830 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1831 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1837 if (ProbeType is PatternExpression) {
1838 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1839 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1845 // TODO: Better error message
1846 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1850 Expression ResolveResultExpression (ResolveContext ec)
1852 TypeSpec d = expr.Type;
1853 bool d_is_nullable = false;
1856 // If E is a method group or the null literal, or if the type of E is a reference
1857 // type or a nullable type and the value of E is null, the result is false
1859 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1860 return CreateConstantResult (ec, false);
1862 if (d.IsNullableType) {
1863 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1864 if (!ut.IsGenericParameter) {
1866 d_is_nullable = true;
1870 TypeSpec t = probe_type_expr;
1871 bool t_is_nullable = false;
1872 if (t.IsNullableType) {
1873 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1874 if (!ut.IsGenericParameter) {
1876 t_is_nullable = true;
1883 // D and T are the same value types but D can be null
1885 if (d_is_nullable && !t_is_nullable) {
1886 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1891 // The result is true if D and T are the same value types
1893 return CreateConstantResult (ec, true);
1896 var tp = d as TypeParameterSpec;
1898 return ResolveGenericParameter (ec, t, tp);
1901 // An unboxing conversion exists
1903 if (Convert.ExplicitReferenceConversionExists (d, t))
1907 // open generic type
1909 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1912 var tps = t as TypeParameterSpec;
1914 return ResolveGenericParameter (ec, d, tps);
1916 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1917 ec.Report.Warning (1981, 3, loc,
1918 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1919 OperatorName, t.GetSignatureForError ());
1922 if (TypeManager.IsGenericParameter (d))
1923 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1925 if (TypeSpec.IsValueType (d)) {
1926 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1927 if (d_is_nullable && !t_is_nullable) {
1928 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1932 return CreateConstantResult (ec, true);
1935 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1936 var c = expr as Constant;
1938 return CreateConstantResult (ec, !c.IsNull);
1941 // Do not optimize for imported type or dynamic type
1943 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1944 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1948 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1952 // Turn is check into simple null check for implicitly convertible reference types
1954 return ReducedExpression.Create (
1955 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1959 if (Convert.ExplicitReferenceConversionExists (d, t))
1963 // open generic type
1965 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1970 return CreateConstantResult (ec, false);
1973 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1975 if (t.IsReferenceType) {
1977 return CreateConstantResult (ec, false);
1980 if (expr.Type.IsGenericParameter) {
1981 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1982 return CreateConstantResult (ec, true);
1984 expr = new BoxedCast (expr, d);
1990 public override object Accept (StructuralVisitor visitor)
1992 return visitor.Visit (this);
1996 class WildcardPattern : PatternExpression
1998 public WildcardPattern (Location loc)
2003 protected override Expression DoResolve (ResolveContext rc)
2005 eclass = ExprClass.Value;
2006 type = rc.BuiltinTypes.Object;
2010 public override void Emit (EmitContext ec)
2016 class RecursivePattern : ComplexPatternExpression
2018 MethodGroupExpr operator_mg;
2019 Arguments operator_args;
2021 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2022 : base (typeExpresion, loc)
2024 Arguments = arguments;
2027 public Arguments Arguments { get; private set; }
2029 protected override Expression DoResolve (ResolveContext rc)
2031 type = TypeExpression.ResolveAsType (rc);
2035 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2036 if (operators == null) {
2037 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2041 var ops = FindMatchingOverloads (operators);
2043 // TODO: better error message
2044 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2049 Arguments.Resolve (rc, out dynamic_args);
2051 throw new NotImplementedException ("dynamic argument");
2053 var op = FindBestOverload (rc, ops);
2055 // TODO: better error message
2056 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2060 var op_types = op.Parameters.Types;
2061 operator_args = new Arguments (op_types.Length);
2062 operator_args.Add (new Argument (new EmptyExpression (type)));
2064 for (int i = 0; i < Arguments.Count; ++i) {
2065 // TODO: Needs releasing optimization
2066 var lt = new LocalTemporary (op_types [i + 1]);
2067 operator_args.Add (new Argument (lt, Argument.AType.Out));
2069 if (comparisons == null)
2070 comparisons = new Expression[Arguments.Count];
2075 var arg = Arguments [i];
2076 var named = arg as NamedArgument;
2077 if (named != null) {
2078 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2079 expr = Arguments [arg_comp_index].Expr;
2085 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2088 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2090 eclass = ExprClass.Value;
2094 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2096 int arg_count = Arguments.Count + 1;
2097 List<MethodSpec> best = null;
2098 foreach (MethodSpec method in members) {
2099 var pm = method.Parameters;
2100 if (pm.Count != arg_count)
2103 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2105 for (int ii = 1; ii < pm.Count; ++ii) {
2106 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2116 best = new List<MethodSpec> ();
2124 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2126 for (int ii = 0; ii < Arguments.Count; ++ii) {
2127 var arg = Arguments [ii];
2128 var expr = arg.Expr;
2129 if (expr is WildcardPattern)
2132 var na = arg as NamedArgument;
2133 for (int i = 0; i < methods.Count; ++i) {
2134 var pd = methods [i].Parameters;
2138 index = pd.GetParameterIndexByName (na.Name);
2140 methods.RemoveAt (i--);
2147 var m = pd.Types [index];
2148 if (!Convert.ImplicitConversionExists (rc, expr, m))
2149 methods.RemoveAt (i--);
2153 if (methods.Count != 1)
2159 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2161 operator_mg.EmitCall (ec, operator_args, false);
2162 ec.Emit (OpCodes.Brfalse, target);
2164 base.EmitBranchable (ec, target, on_true);
2167 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2169 if (expr is WildcardPattern)
2170 return new EmptyExpression (expr.Type);
2172 var recursive = expr as RecursivePattern;
2173 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2177 if (recursive != null) {
2178 recursive.SetParentInstance (lt);
2182 // TODO: Better error handling
2183 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2186 public void SetParentInstance (Expression instance)
2188 operator_args [0] = new Argument (instance);
2192 class PropertyPattern : ComplexPatternExpression
2194 LocalTemporary instance;
2196 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2197 : base (typeExpresion, loc)
2202 public List<PropertyPatternMember> Members { get; private set; }
2204 protected override Expression DoResolve (ResolveContext rc)
2206 type = TypeExpression.ResolveAsType (rc);
2210 comparisons = new Expression[Members.Count];
2212 // TODO: optimize when source is VariableReference, it'd save dup+pop
2213 instance = new LocalTemporary (type);
2215 for (int i = 0; i < Members.Count; i++) {
2216 var lookup = Members [i];
2218 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2219 if (member == null) {
2220 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2221 if (member != null) {
2222 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2227 if (member == null) {
2228 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2232 var pe = member as PropertyExpr;
2233 if (pe == null || member is FieldExpr) {
2234 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2238 // TODO: Obsolete checks
2239 // TODO: check accessibility
2240 if (pe != null && !pe.PropertyInfo.HasGet) {
2241 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2245 var expr = lookup.Expr.Resolve (rc);
2249 var me = (MemberExpr)member;
2250 me.InstanceExpression = instance;
2252 comparisons [i] = ResolveComparison (rc, expr, me);
2255 eclass = ExprClass.Value;
2259 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2261 if (expr is WildcardPattern)
2262 return new EmptyExpression (expr.Type);
2264 return new Is (instance, expr, expr.Location).Resolve (rc);
2267 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2269 instance.Store (ec);
2271 base.EmitBranchable (ec, target, on_true);
2275 class PropertyPatternMember
2277 public PropertyPatternMember (string name, Expression expr, Location loc)
2284 public string Name { get; private set; }
2285 public Expression Expr { get; private set; }
2286 public Location Location { get; private set; }
2289 abstract class PatternExpression : Expression
2291 protected PatternExpression (Location loc)
2296 public override Expression CreateExpressionTree (ResolveContext ec)
2298 throw new NotImplementedException ();
2302 abstract class ComplexPatternExpression : PatternExpression
2304 protected Expression[] comparisons;
2306 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2309 TypeExpression = typeExpresion;
2312 public ATypeNameExpression TypeExpression { get; private set; }
2314 public override void Emit (EmitContext ec)
2316 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2319 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2321 if (comparisons != null) {
2322 foreach (var comp in comparisons) {
2323 comp.EmitBranchable (ec, target, false);
2330 /// Implementation of the `as' operator.
2332 public class As : Probe {
2334 public As (Expression expr, Expression probe_type, Location l)
2335 : base (expr, probe_type, l)
2339 protected override string OperatorName {
2340 get { return "as"; }
2343 public override Expression CreateExpressionTree (ResolveContext ec)
2345 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2346 expr.CreateExpressionTree (ec),
2347 new TypeOf (probe_type_expr, loc));
2349 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2352 public override void Emit (EmitContext ec)
2356 ec.Emit (OpCodes.Isinst, type);
2358 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2359 ec.Emit (OpCodes.Unbox_Any, type);
2362 protected override Expression DoResolve (ResolveContext ec)
2364 if (ResolveCommon (ec) == null)
2367 type = probe_type_expr;
2368 eclass = ExprClass.Value;
2369 TypeSpec etype = expr.Type;
2372 type = InternalType.ErrorType;
2376 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2377 if (TypeManager.IsGenericParameter (type)) {
2378 ec.Report.Error (413, loc,
2379 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2380 probe_type_expr.GetSignatureForError ());
2382 ec.Report.Error (77, loc,
2383 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2384 type.GetSignatureForError ());
2389 if (expr.IsNull && type.IsNullableType) {
2390 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2393 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2394 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2398 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2400 e = EmptyCast.Create (e, type);
2401 return ReducedExpression.Create (e, this).Resolve (ec);
2404 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2405 if (TypeManager.IsGenericParameter (etype))
2406 expr = new BoxedCast (expr, etype);
2411 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2412 expr = new BoxedCast (expr, etype);
2416 if (etype != InternalType.ErrorType) {
2417 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2418 etype.GetSignatureForError (), type.GetSignatureForError ());
2424 public override object Accept (StructuralVisitor visitor)
2426 return visitor.Visit (this);
2431 // This represents a typecast in the source language.
2433 public class Cast : ShimExpression {
2434 Expression target_type;
2436 public Cast (Expression cast_type, Expression expr, Location loc)
2439 this.target_type = cast_type;
2443 public Expression TargetType {
2444 get { return target_type; }
2447 protected override Expression DoResolve (ResolveContext ec)
2449 expr = expr.Resolve (ec);
2453 type = target_type.ResolveAsType (ec);
2457 if (type.IsStatic) {
2458 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2462 if (type.IsPointer) {
2463 if (ec.CurrentIterator != null) {
2464 UnsafeInsideIteratorError (ec, loc);
2465 } else if (!ec.IsUnsafe) {
2466 UnsafeError (ec, loc);
2470 eclass = ExprClass.Value;
2472 Constant c = expr as Constant;
2474 c = c.Reduce (ec, type);
2479 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2481 return EmptyCast.Create (res, type);
2486 protected override void CloneTo (CloneContext clonectx, Expression t)
2488 Cast target = (Cast) t;
2490 target.target_type = target_type.Clone (clonectx);
2491 target.expr = expr.Clone (clonectx);
2494 public override object Accept (StructuralVisitor visitor)
2496 return visitor.Visit (this);
2500 public class ImplicitCast : ShimExpression
2504 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2507 this.loc = expr.Location;
2509 this.arrayAccess = arrayAccess;
2512 protected override Expression DoResolve (ResolveContext ec)
2514 expr = expr.Resolve (ec);
2519 expr = ConvertExpressionToArrayIndex (ec, expr);
2521 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2527 public class DeclarationExpression : Expression, IMemoryLocation
2529 LocalVariableReference lvr;
2531 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2533 VariableType = variableType;
2534 Variable = variable;
2535 this.loc = variable.Location;
2538 public LocalVariable Variable { get; set; }
2539 public Expression Initializer { get; set; }
2540 public FullNamedExpression VariableType { get; set; }
2542 public void AddressOf (EmitContext ec, AddressOp mode)
2544 Variable.CreateBuilder (ec);
2546 if (Initializer != null) {
2547 lvr.EmitAssign (ec, Initializer, false, false);
2550 lvr.AddressOf (ec, mode);
2553 protected override void CloneTo (CloneContext clonectx, Expression t)
2555 var target = (DeclarationExpression) t;
2557 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2559 if (Initializer != null)
2560 target.Initializer = Initializer.Clone (clonectx);
2563 public override Expression CreateExpressionTree (ResolveContext rc)
2565 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2569 bool DoResolveCommon (ResolveContext rc)
2571 if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
2572 rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
2573 } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
2574 rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
2577 var var_expr = VariableType as VarExpr;
2578 if (var_expr != null) {
2579 type = InternalType.VarOutType;
2581 type = VariableType.ResolveAsType (rc);
2586 if (Initializer != null) {
2587 Initializer = Initializer.Resolve (rc);
2589 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2590 type = var_expr.Type;
2594 Variable.Type = type;
2595 lvr = new LocalVariableReference (Variable, loc);
2597 eclass = ExprClass.Variable;
2601 protected override Expression DoResolve (ResolveContext rc)
2603 if (DoResolveCommon (rc))
2609 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2611 if (lvr == null && DoResolveCommon (rc))
2612 lvr.ResolveLValue (rc, right_side);
2617 public override void Emit (EmitContext ec)
2619 throw new NotImplementedException ();
2624 // C# 2.0 Default value expression
2626 public class DefaultValueExpression : Expression
2630 public DefaultValueExpression (Expression expr, Location loc)
2636 public Expression Expr {
2642 public override bool IsSideEffectFree {
2648 public override bool ContainsEmitWithAwait ()
2653 public override Expression CreateExpressionTree (ResolveContext ec)
2655 Arguments args = new Arguments (2);
2656 args.Add (new Argument (this));
2657 args.Add (new Argument (new TypeOf (type, loc)));
2658 return CreateExpressionFactoryCall (ec, "Constant", args);
2661 protected override Expression DoResolve (ResolveContext ec)
2663 type = expr.ResolveAsType (ec);
2667 if (type.IsStatic) {
2668 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2672 return new NullLiteral (Location).ConvertImplicitly (type);
2674 if (TypeSpec.IsReferenceType (type))
2675 return new NullConstant (type, loc);
2677 Constant c = New.Constantify (type, expr.Location);
2681 eclass = ExprClass.Variable;
2685 public override void Emit (EmitContext ec)
2687 LocalTemporary temp_storage = new LocalTemporary(type);
2689 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2690 ec.Emit(OpCodes.Initobj, type);
2691 temp_storage.Emit(ec);
2692 temp_storage.Release (ec);
2696 public override SLE.Expression MakeExpression (BuilderContext ctx)
2698 return SLE.Expression.Default (type.GetMetaInfo ());
2702 protected override void CloneTo (CloneContext clonectx, Expression t)
2704 DefaultValueExpression target = (DefaultValueExpression) t;
2706 target.expr = expr.Clone (clonectx);
2709 public override object Accept (StructuralVisitor visitor)
2711 return visitor.Visit (this);
2716 /// Binary operators
2718 public class Binary : Expression, IDynamicBinder
2720 public class PredefinedOperator
2722 protected readonly TypeSpec left;
2723 protected readonly TypeSpec right;
2724 protected readonly TypeSpec left_unwrap;
2725 protected readonly TypeSpec right_unwrap;
2726 public readonly Operator OperatorsMask;
2727 public TypeSpec ReturnType;
2729 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2730 : this (ltype, rtype, op_mask, ltype)
2734 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2735 : this (type, type, op_mask, return_type)
2739 public PredefinedOperator (TypeSpec type, Operator op_mask)
2740 : this (type, type, op_mask, type)
2744 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2746 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2747 throw new InternalErrorException ("Only masked values can be used");
2749 if ((op_mask & Operator.NullableMask) != 0) {
2750 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2751 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2753 left_unwrap = ltype;
2754 right_unwrap = rtype;
2759 this.OperatorsMask = op_mask;
2760 this.ReturnType = return_type;
2763 public bool IsLifted {
2765 return (OperatorsMask & Operator.NullableMask) != 0;
2769 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2773 var left_expr = b.left;
2774 var right_expr = b.right;
2776 b.type = ReturnType;
2779 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2780 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2781 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2784 if (right_expr.IsNull) {
2785 if ((b.oper & Operator.EqualityMask) != 0) {
2786 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2787 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2788 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2789 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2790 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2792 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2793 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2795 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2796 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2798 return b.CreateLiftedValueTypeResult (rc, left);
2800 } else if (left_expr.IsNull) {
2801 if ((b.oper & Operator.EqualityMask) != 0) {
2802 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2803 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2804 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2805 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2806 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2808 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2809 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2811 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2812 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2814 return b.CreateLiftedValueTypeResult (rc, right);
2820 // A user operators does not support multiple user conversions, but decimal type
2821 // is considered to be predefined type therefore we apply predefined operators rules
2822 // and then look for decimal user-operator implementation
2824 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2825 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2826 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2828 return b.ResolveUserOperator (rc, b.left, b.right);
2831 c = right_expr as Constant;
2833 if (c.IsDefaultValue) {
2837 // (expr + 0) to expr
2838 // (expr - 0) to expr
2839 // (bool? | false) to bool?
2841 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2842 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2843 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2844 return ReducedExpression.Create (b.left, b).Resolve (rc);
2848 // Optimizes (value &/&& 0) to 0
2850 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2851 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2852 return ReducedExpression.Create (side_effect, b);
2856 // Optimizes (bool? & true) to bool?
2858 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2859 return ReducedExpression.Create (b.left, b).Resolve (rc);
2863 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2864 return ReducedExpression.Create (b.left, b).Resolve (rc);
2866 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2867 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2871 c = b.left as Constant;
2873 if (c.IsDefaultValue) {
2877 // (0 + expr) to expr
2878 // (false | bool?) to bool?
2880 if (b.oper == Operator.Addition ||
2881 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2882 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2883 return ReducedExpression.Create (b.right, b).Resolve (rc);
2887 // Optimizes (false && expr) to false
2889 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2890 // No rhs side-effects
2891 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2892 return ReducedExpression.Create (c, b);
2896 // Optimizes (0 & value) to 0
2898 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2899 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2900 return ReducedExpression.Create (side_effect, b);
2904 // Optimizes (true & bool?) to bool?
2906 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2907 return ReducedExpression.Create (b.right, b).Resolve (rc);
2911 // Optimizes (true || expr) to true
2913 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2914 // No rhs side-effects
2915 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2916 return ReducedExpression.Create (c, b);
2920 if (b.oper == Operator.Multiply && c.IsOneInteger)
2921 return ReducedExpression.Create (b.right, b).Resolve (rc);
2925 var lifted = new Nullable.LiftedBinaryOperator (b);
2927 TypeSpec ltype, rtype;
2928 if (b.left.Type.IsNullableType) {
2929 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2930 ltype = left_unwrap;
2935 if (b.right.Type.IsNullableType) {
2936 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2937 rtype = right_unwrap;
2942 lifted.Left = b.left.IsNull ?
2943 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2944 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2946 lifted.Right = b.right.IsNull ?
2947 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2948 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2950 return lifted.Resolve (rc);
2953 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2954 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2959 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2962 // We are dealing with primitive types only
2964 return left == ltype && ltype == rtype;
2967 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2970 if (left == lexpr.Type && right == rexpr.Type)
2973 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2974 Convert.ImplicitConversionExists (ec, rexpr, right);
2977 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2979 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2980 return best_operator;
2982 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2986 if (left != null && best_operator.left != null) {
2987 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2991 // When second argument is same as the first one, the result is same
2993 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2994 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2997 if (result == 0 || result > 2)
3000 return result == 1 ? best_operator : this;
3004 sealed class PredefinedStringOperator : PredefinedOperator
3006 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3007 : base (type, type, op_mask, retType)
3011 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3012 : base (ltype, rtype, op_mask, retType)
3016 public override Expression ConvertResult (ResolveContext ec, Binary b)
3019 // Use original expression for nullable arguments
3021 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3023 b.left = unwrap.Original;
3025 unwrap = b.right as Nullable.Unwrap;
3027 b.right = unwrap.Original;
3029 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3030 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3033 // Start a new concat expression using converted expression
3035 return StringConcat.Create (ec, b.left, b.right, b.loc);
3039 sealed class PredefinedEqualityOperator : PredefinedOperator
3041 MethodSpec equal_method, inequal_method;
3043 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3044 : base (arg, arg, Operator.EqualityMask, retType)
3048 public override Expression ConvertResult (ResolveContext ec, Binary b)
3050 b.type = ReturnType;
3052 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3053 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3055 Arguments args = new Arguments (2);
3056 args.Add (new Argument (b.left));
3057 args.Add (new Argument (b.right));
3060 if (b.oper == Operator.Equality) {
3061 if (equal_method == null) {
3062 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3063 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3064 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3065 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3067 throw new NotImplementedException (left.GetSignatureForError ());
3070 method = equal_method;
3072 if (inequal_method == null) {
3073 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3074 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3075 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3076 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3078 throw new NotImplementedException (left.GetSignatureForError ());
3081 method = inequal_method;
3084 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3088 class PredefinedPointerOperator : PredefinedOperator
3090 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3091 : base (ltype, rtype, op_mask)
3095 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3096 : base (ltype, rtype, op_mask, retType)
3100 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3101 : base (type, op_mask, return_type)
3105 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3108 if (!lexpr.Type.IsPointer)
3111 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3115 if (right == null) {
3116 if (!rexpr.Type.IsPointer)
3119 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3126 public override Expression ConvertResult (ResolveContext ec, Binary b)
3129 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3130 } else if (right != null) {
3131 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3134 TypeSpec r_type = ReturnType;
3135 Expression left_arg, right_arg;
3136 if (r_type == null) {
3139 right_arg = b.right;
3140 r_type = b.left.Type;
3144 r_type = b.right.Type;
3148 right_arg = b.right;
3151 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3156 public enum Operator {
3157 Multiply = 0 | ArithmeticMask,
3158 Division = 1 | ArithmeticMask,
3159 Modulus = 2 | ArithmeticMask,
3160 Addition = 3 | ArithmeticMask | AdditionMask,
3161 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3163 LeftShift = 5 | ShiftMask,
3164 RightShift = 6 | ShiftMask,
3166 LessThan = 7 | ComparisonMask | RelationalMask,
3167 GreaterThan = 8 | ComparisonMask | RelationalMask,
3168 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3169 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3170 Equality = 11 | ComparisonMask | EqualityMask,
3171 Inequality = 12 | ComparisonMask | EqualityMask,
3173 BitwiseAnd = 13 | BitwiseMask,
3174 ExclusiveOr = 14 | BitwiseMask,
3175 BitwiseOr = 15 | BitwiseMask,
3177 LogicalAnd = 16 | LogicalMask,
3178 LogicalOr = 17 | LogicalMask,
3183 ValuesOnlyMask = ArithmeticMask - 1,
3184 ArithmeticMask = 1 << 5,
3186 ComparisonMask = 1 << 7,
3187 EqualityMask = 1 << 8,
3188 BitwiseMask = 1 << 9,
3189 LogicalMask = 1 << 10,
3190 AdditionMask = 1 << 11,
3191 SubtractionMask = 1 << 12,
3192 RelationalMask = 1 << 13,
3194 DecomposedMask = 1 << 19,
3195 NullableMask = 1 << 20
3199 public enum State : byte
3203 UserOperatorsExcluded = 1 << 2
3206 readonly Operator oper;
3207 Expression left, right;
3209 ConvCast.Mode enum_conversion;
3211 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3212 : this (oper, left, right, State.Compound)
3216 public Binary (Operator oper, Expression left, Expression right, State state)
3217 : this (oper, left, right)
3222 public Binary (Operator oper, Expression left, Expression right)
3223 : this (oper, left, right, left.Location)
3227 public Binary (Operator oper, Expression left, Expression right, Location loc)
3237 public bool IsCompound {
3239 return (state & State.Compound) != 0;
3243 public Operator Oper {
3249 public Expression Left {
3255 public Expression Right {
3261 public override Location StartLocation {
3263 return left.StartLocation;
3270 /// Returns a stringified representation of the Operator
3272 string OperName (Operator oper)
3276 case Operator.Multiply:
3279 case Operator.Division:
3282 case Operator.Modulus:
3285 case Operator.Addition:
3288 case Operator.Subtraction:
3291 case Operator.LeftShift:
3294 case Operator.RightShift:
3297 case Operator.LessThan:
3300 case Operator.GreaterThan:
3303 case Operator.LessThanOrEqual:
3306 case Operator.GreaterThanOrEqual:
3309 case Operator.Equality:
3312 case Operator.Inequality:
3315 case Operator.BitwiseAnd:
3318 case Operator.BitwiseOr:
3321 case Operator.ExclusiveOr:
3324 case Operator.LogicalOr:
3327 case Operator.LogicalAnd:
3331 s = oper.ToString ();
3341 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3343 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3346 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3348 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3352 l = left.Type.GetSignatureForError ();
3353 r = right.Type.GetSignatureForError ();
3355 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3359 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3361 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3364 public override void FlowAnalysis (FlowAnalysisContext fc)
3367 // Optimized version when on-true/on-false data are not needed
3369 if ((oper & Operator.LogicalMask) == 0) {
3370 left.FlowAnalysis (fc);
3371 right.FlowAnalysis (fc);
3375 left.FlowAnalysisConditional (fc);
3376 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3377 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3379 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3380 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3381 right.FlowAnalysisConditional (fc);
3383 if (oper == Operator.LogicalOr)
3384 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3386 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3389 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3391 if ((oper & Operator.LogicalMask) == 0) {
3392 base.FlowAnalysisConditional (fc);
3396 left.FlowAnalysisConditional (fc);
3397 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3398 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3400 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3401 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3402 right.FlowAnalysisConditional (fc);
3404 var lc = left as Constant;
3405 if (oper == Operator.LogicalOr) {
3406 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3407 if (lc != null && lc.IsDefaultValue)
3408 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3410 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3412 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3413 if (lc != null && !lc.IsDefaultValue)
3414 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3416 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3421 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3423 string GetOperatorExpressionTypeName ()
3426 case Operator.Addition:
3427 return IsCompound ? "AddAssign" : "Add";
3428 case Operator.BitwiseAnd:
3429 return IsCompound ? "AndAssign" : "And";
3430 case Operator.BitwiseOr:
3431 return IsCompound ? "OrAssign" : "Or";
3432 case Operator.Division:
3433 return IsCompound ? "DivideAssign" : "Divide";
3434 case Operator.ExclusiveOr:
3435 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3436 case Operator.Equality:
3438 case Operator.GreaterThan:
3439 return "GreaterThan";
3440 case Operator.GreaterThanOrEqual:
3441 return "GreaterThanOrEqual";
3442 case Operator.Inequality:
3444 case Operator.LeftShift:
3445 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3446 case Operator.LessThan:
3448 case Operator.LessThanOrEqual:
3449 return "LessThanOrEqual";
3450 case Operator.LogicalAnd:
3452 case Operator.LogicalOr:
3454 case Operator.Modulus:
3455 return IsCompound ? "ModuloAssign" : "Modulo";
3456 case Operator.Multiply:
3457 return IsCompound ? "MultiplyAssign" : "Multiply";
3458 case Operator.RightShift:
3459 return IsCompound ? "RightShiftAssign" : "RightShift";
3460 case Operator.Subtraction:
3461 return IsCompound ? "SubtractAssign" : "Subtract";
3463 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3467 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3470 case Operator.Addition:
3471 return CSharp.Operator.OpType.Addition;
3472 case Operator.BitwiseAnd:
3473 case Operator.LogicalAnd:
3474 return CSharp.Operator.OpType.BitwiseAnd;
3475 case Operator.BitwiseOr:
3476 case Operator.LogicalOr:
3477 return CSharp.Operator.OpType.BitwiseOr;
3478 case Operator.Division:
3479 return CSharp.Operator.OpType.Division;
3480 case Operator.Equality:
3481 return CSharp.Operator.OpType.Equality;
3482 case Operator.ExclusiveOr:
3483 return CSharp.Operator.OpType.ExclusiveOr;
3484 case Operator.GreaterThan:
3485 return CSharp.Operator.OpType.GreaterThan;
3486 case Operator.GreaterThanOrEqual:
3487 return CSharp.Operator.OpType.GreaterThanOrEqual;
3488 case Operator.Inequality:
3489 return CSharp.Operator.OpType.Inequality;
3490 case Operator.LeftShift:
3491 return CSharp.Operator.OpType.LeftShift;
3492 case Operator.LessThan:
3493 return CSharp.Operator.OpType.LessThan;
3494 case Operator.LessThanOrEqual:
3495 return CSharp.Operator.OpType.LessThanOrEqual;
3496 case Operator.Modulus:
3497 return CSharp.Operator.OpType.Modulus;
3498 case Operator.Multiply:
3499 return CSharp.Operator.OpType.Multiply;
3500 case Operator.RightShift:
3501 return CSharp.Operator.OpType.RightShift;
3502 case Operator.Subtraction:
3503 return CSharp.Operator.OpType.Subtraction;
3505 throw new InternalErrorException (op.ToString ());
3509 public override bool ContainsEmitWithAwait ()
3511 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3514 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3519 case Operator.Multiply:
3520 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3521 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3522 opcode = OpCodes.Mul_Ovf;
3523 else if (!IsFloat (l))
3524 opcode = OpCodes.Mul_Ovf_Un;
3526 opcode = OpCodes.Mul;
3528 opcode = OpCodes.Mul;
3532 case Operator.Division:
3534 opcode = OpCodes.Div_Un;
3536 opcode = OpCodes.Div;
3539 case Operator.Modulus:
3541 opcode = OpCodes.Rem_Un;
3543 opcode = OpCodes.Rem;
3546 case Operator.Addition:
3547 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3548 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3549 opcode = OpCodes.Add_Ovf;
3550 else if (!IsFloat (l))
3551 opcode = OpCodes.Add_Ovf_Un;
3553 opcode = OpCodes.Add;
3555 opcode = OpCodes.Add;
3558 case Operator.Subtraction:
3559 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3560 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3561 opcode = OpCodes.Sub_Ovf;
3562 else if (!IsFloat (l))
3563 opcode = OpCodes.Sub_Ovf_Un;
3565 opcode = OpCodes.Sub;
3567 opcode = OpCodes.Sub;
3570 case Operator.RightShift:
3571 if (!(right is IntConstant)) {
3572 ec.EmitInt (GetShiftMask (l));
3573 ec.Emit (OpCodes.And);
3577 opcode = OpCodes.Shr_Un;
3579 opcode = OpCodes.Shr;
3582 case Operator.LeftShift:
3583 if (!(right is IntConstant)) {
3584 ec.EmitInt (GetShiftMask (l));
3585 ec.Emit (OpCodes.And);
3588 opcode = OpCodes.Shl;
3591 case Operator.Equality:
3592 opcode = OpCodes.Ceq;
3595 case Operator.Inequality:
3596 ec.Emit (OpCodes.Ceq);
3599 opcode = OpCodes.Ceq;
3602 case Operator.LessThan:
3604 opcode = OpCodes.Clt_Un;
3606 opcode = OpCodes.Clt;
3609 case Operator.GreaterThan:
3611 opcode = OpCodes.Cgt_Un;
3613 opcode = OpCodes.Cgt;
3616 case Operator.LessThanOrEqual:
3617 if (IsUnsigned (l) || IsFloat (l))
3618 ec.Emit (OpCodes.Cgt_Un);
3620 ec.Emit (OpCodes.Cgt);
3623 opcode = OpCodes.Ceq;
3626 case Operator.GreaterThanOrEqual:
3627 if (IsUnsigned (l) || IsFloat (l))
3628 ec.Emit (OpCodes.Clt_Un);
3630 ec.Emit (OpCodes.Clt);
3634 opcode = OpCodes.Ceq;
3637 case Operator.BitwiseOr:
3638 opcode = OpCodes.Or;
3641 case Operator.BitwiseAnd:
3642 opcode = OpCodes.And;
3645 case Operator.ExclusiveOr:
3646 opcode = OpCodes.Xor;
3650 throw new InternalErrorException (oper.ToString ());
3656 static int GetShiftMask (TypeSpec type)
3658 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3661 static bool IsUnsigned (TypeSpec t)
3663 switch (t.BuiltinType) {
3664 case BuiltinTypeSpec.Type.Char:
3665 case BuiltinTypeSpec.Type.UInt:
3666 case BuiltinTypeSpec.Type.ULong:
3667 case BuiltinTypeSpec.Type.UShort:
3668 case BuiltinTypeSpec.Type.Byte:
3675 static bool IsFloat (TypeSpec t)
3677 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3680 public Expression ResolveOperator (ResolveContext rc)
3682 eclass = ExprClass.Value;
3684 TypeSpec l = left.Type;
3685 TypeSpec r = right.Type;
3687 bool primitives_only = false;
3690 // Handles predefined primitive types
3692 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3693 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3694 if ((oper & Operator.ShiftMask) == 0) {
3695 if (!DoBinaryOperatorPromotion (rc))
3698 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3702 if (l.IsPointer || r.IsPointer)
3703 return ResolveOperatorPointer (rc, l, r);
3706 if ((state & State.UserOperatorsExcluded) == 0) {
3707 expr = ResolveUserOperator (rc, left, right);
3712 bool lenum = l.IsEnum;
3713 bool renum = r.IsEnum;
3714 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3718 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3719 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3724 if ((oper & Operator.BitwiseMask) != 0) {
3725 expr = EmptyCast.Create (expr, type);
3726 enum_conversion = GetEnumResultCast (type);
3728 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3729 expr = OptimizeAndOperation (expr);
3733 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3734 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3737 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3738 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3742 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3745 // We cannot break here there is also Enum + String possible match
3746 // which is not ambiguous with predefined enum operators
3749 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3750 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3754 } else if (l.IsDelegate || r.IsDelegate) {
3758 expr = ResolveOperatorDelegate (rc, l, r);
3760 // TODO: Can this be ambiguous
3768 // Equality operators are more complicated
3770 if ((oper & Operator.EqualityMask) != 0) {
3771 return ResolveEquality (rc, l, r, primitives_only);
3774 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3778 if (primitives_only)
3782 // Lifted operators have lower priority
3784 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3787 static bool IsEnumOrNullableEnum (TypeSpec type)
3789 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3793 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3794 // if 'left' is not an enumeration constant, create one from the type of 'right'
3795 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3798 case Operator.BitwiseOr:
3799 case Operator.BitwiseAnd:
3800 case Operator.ExclusiveOr:
3801 case Operator.Equality:
3802 case Operator.Inequality:
3803 case Operator.LessThan:
3804 case Operator.LessThanOrEqual:
3805 case Operator.GreaterThan:
3806 case Operator.GreaterThanOrEqual:
3807 if (left.Type.IsEnum)
3810 if (left.IsZeroInteger)
3811 return left.Reduce (ec, right.Type);
3815 case Operator.Addition:
3816 case Operator.Subtraction:
3819 case Operator.Multiply:
3820 case Operator.Division:
3821 case Operator.Modulus:
3822 case Operator.LeftShift:
3823 case Operator.RightShift:
3824 if (right.Type.IsEnum || left.Type.IsEnum)
3833 // The `|' operator used on types which were extended is dangerous
3835 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3837 OpcodeCast lcast = left as OpcodeCast;
3838 if (lcast != null) {
3839 if (IsUnsigned (lcast.UnderlyingType))
3843 OpcodeCast rcast = right as OpcodeCast;
3844 if (rcast != null) {
3845 if (IsUnsigned (rcast.UnderlyingType))
3849 if (lcast == null && rcast == null)
3852 // FIXME: consider constants
3854 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3855 ec.Report.Warning (675, 3, loc,
3856 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3857 ltype.GetSignatureForError ());
3860 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3862 return new PredefinedOperator[] {
3864 // Pointer arithmetic:
3866 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3867 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3868 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3869 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3871 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3872 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3873 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3874 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3877 // T* operator + (int y, T* x);
3878 // T* operator + (uint y, T *x);
3879 // T* operator + (long y, T *x);
3880 // T* operator + (ulong y, T *x);
3882 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3883 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3884 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3885 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3888 // long operator - (T* x, T *y)
3890 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3894 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3896 TypeSpec bool_type = types.Bool;
3899 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3900 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3901 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3902 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3903 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3904 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3905 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3907 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3908 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3909 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3910 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3911 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3912 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3913 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3915 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3916 // Remaining string operators are in lifted tables
3918 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3920 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3921 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3922 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3926 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3928 var types = module.Compiler.BuiltinTypes;
3931 // Not strictly lifted but need to be in second group otherwise expressions like
3932 // int + null would resolve to +(object, string) instead of +(int?, int?)
3934 var string_operators = new [] {
3935 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3936 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3939 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3940 if (nullable == null)
3941 return string_operators;
3943 var bool_type = types.Bool;
3945 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3946 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3947 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3948 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3949 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3950 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3951 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3952 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3955 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3956 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3957 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3958 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3959 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3960 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3961 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3963 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3964 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3965 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3966 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3967 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3968 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3969 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3971 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3973 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3974 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3975 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3977 string_operators [0],
3978 string_operators [1]
3982 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3984 TypeSpec bool_type = types.Bool;
3987 new PredefinedEqualityOperator (types.String, bool_type),
3988 new PredefinedEqualityOperator (types.Delegate, bool_type),
3989 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3990 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3991 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3992 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3993 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3994 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3995 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3996 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4000 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4002 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4004 if (nullable == null)
4005 return new PredefinedOperator [0];
4007 var types = module.Compiler.BuiltinTypes;
4008 var bool_type = types.Bool;
4009 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4010 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4011 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4012 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4013 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4014 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4015 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4016 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4019 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4020 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4021 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4022 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4023 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4024 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4025 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4026 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4031 // 7.2.6.2 Binary numeric promotions
4033 bool DoBinaryOperatorPromotion (ResolveContext rc)
4035 TypeSpec ltype = left.Type;
4036 if (ltype.IsNullableType) {
4037 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4041 // This is numeric promotion code only
4043 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4046 TypeSpec rtype = right.Type;
4047 if (rtype.IsNullableType) {
4048 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4051 var lb = ltype.BuiltinType;
4052 var rb = rtype.BuiltinType;
4056 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4057 type = rc.BuiltinTypes.Decimal;
4058 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4059 type = rc.BuiltinTypes.Double;
4060 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4061 type = rc.BuiltinTypes.Float;
4062 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4063 type = rc.BuiltinTypes.ULong;
4065 if (IsSignedType (lb)) {
4066 expr = ConvertSignedConstant (left, type);
4070 } else if (IsSignedType (rb)) {
4071 expr = ConvertSignedConstant (right, type);
4077 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4078 type = rc.BuiltinTypes.Long;
4079 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4080 type = rc.BuiltinTypes.UInt;
4082 if (IsSignedType (lb)) {
4083 expr = ConvertSignedConstant (left, type);
4085 type = rc.BuiltinTypes.Long;
4086 } else if (IsSignedType (rb)) {
4087 expr = ConvertSignedConstant (right, type);
4089 type = rc.BuiltinTypes.Long;
4092 type = rc.BuiltinTypes.Int;
4095 if (ltype != type) {
4096 expr = PromoteExpression (rc, left, type);
4103 if (rtype != type) {
4104 expr = PromoteExpression (rc, right, type);
4114 static bool IsSignedType (BuiltinTypeSpec.Type type)
4117 case BuiltinTypeSpec.Type.Int:
4118 case BuiltinTypeSpec.Type.Short:
4119 case BuiltinTypeSpec.Type.SByte:
4120 case BuiltinTypeSpec.Type.Long:
4127 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4129 var c = expr as Constant;
4133 return c.ConvertImplicitly (type);
4136 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4138 if (expr.Type.IsNullableType) {
4139 return Convert.ImplicitConversionStandard (rc, expr,
4140 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4143 var c = expr as Constant;
4145 return c.ConvertImplicitly (type);
4147 return Convert.ImplicitNumericConversion (expr, type);
4150 protected override Expression DoResolve (ResolveContext ec)
4155 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4156 left = ((ParenthesizedExpression) left).Expr;
4157 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4161 if (left.eclass == ExprClass.Type) {
4162 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4166 left = left.Resolve (ec);
4171 right = right.Resolve (ec);
4175 Constant lc = left as Constant;
4176 Constant rc = right as Constant;
4178 // The conversion rules are ignored in enum context but why
4179 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4180 lc = EnumLiftUp (ec, lc, rc);
4182 rc = EnumLiftUp (ec, rc, lc);
4185 if (rc != null && lc != null) {
4186 int prev_e = ec.Report.Errors;
4187 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4188 if (e != null || ec.Report.Errors != prev_e)
4192 // Comparison warnings
4193 if ((oper & Operator.ComparisonMask) != 0) {
4194 if (left.Equals (right)) {
4195 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4197 CheckOutOfRangeComparison (ec, lc, right.Type);
4198 CheckOutOfRangeComparison (ec, rc, left.Type);
4201 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4202 return DoResolveDynamic (ec);
4204 return DoResolveCore (ec, left, right);
4207 Expression DoResolveDynamic (ResolveContext rc)
4210 var rt = right.Type;
4211 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4212 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4213 Error_OperatorCannotBeApplied (rc, left, right);
4220 // Special handling for logical boolean operators which require rhs not to be
4221 // evaluated based on lhs value
4223 if ((oper & Operator.LogicalMask) != 0) {
4224 Expression cond_left, cond_right, expr;
4226 args = new Arguments (2);
4228 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4229 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4231 var cond_args = new Arguments (1);
4232 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4235 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4236 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4238 left = temp.CreateReferenceExpression (rc, loc);
4239 if (oper == Operator.LogicalAnd) {
4240 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4243 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4247 args.Add (new Argument (left));
4248 args.Add (new Argument (right));
4249 cond_right = new DynamicExpressionStatement (this, args, loc);
4251 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4253 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4254 rc.Report.Error (7083, left.Location,
4255 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4256 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4260 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4261 args.Add (new Argument (right));
4262 right = new DynamicExpressionStatement (this, args, loc);
4265 // bool && dynamic => (temp = left) ? temp && right : temp;
4266 // bool || dynamic => (temp = left) ? temp : temp || right;
4268 if (oper == Operator.LogicalAnd) {
4270 cond_right = temp.CreateReferenceExpression (rc, loc);
4272 cond_left = temp.CreateReferenceExpression (rc, loc);
4276 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4279 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4282 args = new Arguments (2);
4283 args.Add (new Argument (left));
4284 args.Add (new Argument (right));
4285 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4288 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4290 Expression expr = ResolveOperator (ec);
4292 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4294 if (left == null || right == null)
4295 throw new InternalErrorException ("Invalid conversion");
4297 if (oper == Operator.BitwiseOr)
4298 CheckBitwiseOrOnSignExtended (ec);
4303 public override SLE.Expression MakeExpression (BuilderContext ctx)
4305 return MakeExpression (ctx, left, right);
4308 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4310 var le = left.MakeExpression (ctx);
4311 var re = right.MakeExpression (ctx);
4312 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4315 case Operator.Addition:
4316 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4317 case Operator.BitwiseAnd:
4318 return SLE.Expression.And (le, re);
4319 case Operator.BitwiseOr:
4320 return SLE.Expression.Or (le, re);
4321 case Operator.Division:
4322 return SLE.Expression.Divide (le, re);
4323 case Operator.Equality:
4324 return SLE.Expression.Equal (le, re);
4325 case Operator.ExclusiveOr:
4326 return SLE.Expression.ExclusiveOr (le, re);
4327 case Operator.GreaterThan:
4328 return SLE.Expression.GreaterThan (le, re);
4329 case Operator.GreaterThanOrEqual:
4330 return SLE.Expression.GreaterThanOrEqual (le, re);
4331 case Operator.Inequality:
4332 return SLE.Expression.NotEqual (le, re);
4333 case Operator.LeftShift:
4334 return SLE.Expression.LeftShift (le, re);
4335 case Operator.LessThan:
4336 return SLE.Expression.LessThan (le, re);
4337 case Operator.LessThanOrEqual:
4338 return SLE.Expression.LessThanOrEqual (le, re);
4339 case Operator.LogicalAnd:
4340 return SLE.Expression.AndAlso (le, re);
4341 case Operator.LogicalOr:
4342 return SLE.Expression.OrElse (le, re);
4343 case Operator.Modulus:
4344 return SLE.Expression.Modulo (le, re);
4345 case Operator.Multiply:
4346 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4347 case Operator.RightShift:
4348 return SLE.Expression.RightShift (le, re);
4349 case Operator.Subtraction:
4350 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4352 throw new NotImplementedException (oper.ToString ());
4357 // D operator + (D x, D y)
4358 // D operator - (D x, D y)
4360 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4362 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4364 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4365 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4370 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4371 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4381 MethodSpec method = null;
4382 Arguments args = new Arguments (2);
4383 args.Add (new Argument (left));
4384 args.Add (new Argument (right));
4386 if (oper == Operator.Addition) {
4387 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4388 } else if (oper == Operator.Subtraction) {
4389 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4393 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4395 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4396 return new ClassCast (expr, l);
4400 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4402 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4405 // bool operator == (E x, E y);
4406 // bool operator != (E x, E y);
4407 // bool operator < (E x, E y);
4408 // bool operator > (E x, E y);
4409 // bool operator <= (E x, E y);
4410 // bool operator >= (E x, E y);
4412 // E operator & (E x, E y);
4413 // E operator | (E x, E y);
4414 // E operator ^ (E x, E y);
4417 if ((oper & Operator.ComparisonMask) != 0) {
4418 type = rc.BuiltinTypes.Bool;
4424 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4430 if (ltype == rtype) {
4434 var lifted = new Nullable.LiftedBinaryOperator (this);
4436 lifted.Right = right;
4437 return lifted.Resolve (rc);
4440 if (renum && !ltype.IsNullableType) {
4441 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4446 } else if (lenum && !rtype.IsNullableType) {
4447 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4455 // Now try lifted version of predefined operator
4457 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4458 if (nullable_type != null) {
4459 if (renum && !ltype.IsNullableType) {
4460 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4462 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4465 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4468 if ((oper & Operator.BitwiseMask) != 0)
4472 if ((oper & Operator.BitwiseMask) != 0)
4473 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4475 return CreateLiftedValueTypeResult (rc, rtype);
4479 var lifted = new Nullable.LiftedBinaryOperator (this);
4481 lifted.Right = right;
4482 return lifted.Resolve (rc);
4484 } else if (lenum && !rtype.IsNullableType) {
4485 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4487 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4490 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4493 if ((oper & Operator.BitwiseMask) != 0)
4497 if ((oper & Operator.BitwiseMask) != 0)
4498 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4500 return CreateLiftedValueTypeResult (rc, ltype);
4504 var lifted = new Nullable.LiftedBinaryOperator (this);
4506 lifted.Right = expr;
4507 return lifted.Resolve (rc);
4509 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4510 Nullable.Unwrap unwrap = null;
4511 if (left.IsNull || right.IsNull) {
4512 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4513 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4515 if ((oper & Operator.RelationalMask) != 0)
4516 return CreateLiftedValueTypeResult (rc, rtype);
4518 if ((oper & Operator.BitwiseMask) != 0)
4519 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4522 return CreateLiftedValueTypeResult (rc, left.Type);
4524 // Equality operators are valid between E? and null
4526 unwrap = new Nullable.Unwrap (right);
4528 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4532 if ((oper & Operator.BitwiseMask) != 0)
4537 var lifted = new Nullable.LiftedBinaryOperator (this);
4539 lifted.Right = right;
4540 lifted.UnwrapRight = unwrap;
4541 return lifted.Resolve (rc);
4543 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4544 Nullable.Unwrap unwrap = null;
4545 if (right.IsNull || left.IsNull) {
4546 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4547 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4549 if ((oper & Operator.RelationalMask) != 0)
4550 return CreateLiftedValueTypeResult (rc, ltype);
4552 if ((oper & Operator.BitwiseMask) != 0)
4553 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4556 return CreateLiftedValueTypeResult (rc, right.Type);
4558 // Equality operators are valid between E? and null
4560 unwrap = new Nullable.Unwrap (left);
4562 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4566 if ((oper & Operator.BitwiseMask) != 0)
4571 var lifted = new Nullable.LiftedBinaryOperator (this);
4573 lifted.UnwrapLeft = unwrap;
4574 lifted.Right = expr;
4575 return lifted.Resolve (rc);
4583 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4585 TypeSpec underlying_type;
4586 if (expr.Type.IsNullableType) {
4587 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4589 underlying_type = EnumSpec.GetUnderlyingType (nt);
4591 underlying_type = nt;
4592 } else if (expr.Type.IsEnum) {
4593 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4595 underlying_type = expr.Type;
4598 switch (underlying_type.BuiltinType) {
4599 case BuiltinTypeSpec.Type.SByte:
4600 case BuiltinTypeSpec.Type.Byte:
4601 case BuiltinTypeSpec.Type.Short:
4602 case BuiltinTypeSpec.Type.UShort:
4603 underlying_type = rc.BuiltinTypes.Int;
4607 if (expr.Type.IsNullableType || liftType)
4608 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4610 if (expr.Type == underlying_type)
4613 return EmptyCast.Create (expr, underlying_type);
4616 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4619 // U operator - (E e, E f)
4620 // E operator - (E e, U x) // Internal decomposition operator
4621 // E operator - (U x, E e) // Internal decomposition operator
4623 // E operator + (E e, U x)
4624 // E operator + (U x, E e)
4633 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4639 if (!enum_type.IsNullableType) {
4640 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4642 if (oper == Operator.Subtraction)
4643 expr = ConvertEnumSubtractionResult (rc, expr);
4645 expr = ConvertEnumAdditionalResult (expr, enum_type);
4647 enum_conversion = GetEnumResultCast (expr.Type);
4652 var nullable = rc.Module.PredefinedTypes.Nullable;
4655 // Don't try nullable version when nullable type is undefined
4657 if (!nullable.IsDefined)
4660 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4663 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4665 if (oper == Operator.Subtraction)
4666 expr = ConvertEnumSubtractionResult (rc, expr);
4668 expr = ConvertEnumAdditionalResult (expr, enum_type);
4670 enum_conversion = GetEnumResultCast (expr.Type);
4676 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4678 return EmptyCast.Create (expr, enumType);
4681 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4684 // Enumeration subtraction has different result type based on
4687 TypeSpec result_type;
4688 if (left.Type == right.Type) {
4689 var c = right as EnumConstant;
4690 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4692 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4693 // E which is not what expressions E - 1 or 0 - E return
4695 result_type = left.Type;
4697 result_type = left.Type.IsNullableType ?
4698 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4699 EnumSpec.GetUnderlyingType (left.Type);
4702 if (IsEnumOrNullableEnum (left.Type)) {
4703 result_type = left.Type;
4705 result_type = right.Type;
4708 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4709 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4712 return EmptyCast.Create (expr, result_type);
4715 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4717 if (type.IsNullableType)
4718 type = Nullable.NullableInfo.GetUnderlyingType (type);
4721 type = EnumSpec.GetUnderlyingType (type);
4723 switch (type.BuiltinType) {
4724 case BuiltinTypeSpec.Type.SByte:
4725 return ConvCast.Mode.I4_I1;
4726 case BuiltinTypeSpec.Type.Byte:
4727 return ConvCast.Mode.I4_U1;
4728 case BuiltinTypeSpec.Type.Short:
4729 return ConvCast.Mode.I4_I2;
4730 case BuiltinTypeSpec.Type.UShort:
4731 return ConvCast.Mode.I4_U2;
4738 // Equality operators rules
4740 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4743 type = ec.BuiltinTypes.Bool;
4744 bool no_arg_conv = false;
4746 if (!primitives_only) {
4749 // a, Both operands are reference-type values or the value null
4750 // b, One operand is a value of type T where T is a type-parameter and
4751 // the other operand is the value null. Furthermore T does not have the
4752 // value type constraint
4754 // LAMESPEC: Very confusing details in the specification, basically any
4755 // reference like type-parameter is allowed
4757 var tparam_l = l as TypeParameterSpec;
4758 var tparam_r = r as TypeParameterSpec;
4759 if (tparam_l != null) {
4760 if (right is NullLiteral) {
4761 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4764 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4768 if (!tparam_l.IsReferenceType)
4771 l = tparam_l.GetEffectiveBase ();
4772 left = new BoxedCast (left, l);
4773 } else if (left is NullLiteral && tparam_r == null) {
4774 if (TypeSpec.IsReferenceType (r))
4777 if (r.Kind == MemberKind.InternalCompilerType)
4781 if (tparam_r != null) {
4782 if (left is NullLiteral) {
4783 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4786 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4790 if (!tparam_r.IsReferenceType)
4793 r = tparam_r.GetEffectiveBase ();
4794 right = new BoxedCast (right, r);
4795 } else if (right is NullLiteral) {
4796 if (TypeSpec.IsReferenceType (l))
4799 if (l.Kind == MemberKind.InternalCompilerType)
4804 // LAMESPEC: method groups can be compared when they convert to other side delegate
4807 if (right.eclass == ExprClass.MethodGroup) {
4808 result = Convert.ImplicitConversion (ec, right, l, loc);
4814 } else if (r.IsDelegate && l != r) {
4817 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4818 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4825 no_arg_conv = l == r && !l.IsStruct;
4830 // bool operator != (string a, string b)
4831 // bool operator == (string a, string b)
4833 // bool operator != (Delegate a, Delegate b)
4834 // bool operator == (Delegate a, Delegate b)
4836 // bool operator != (bool a, bool b)
4837 // bool operator == (bool a, bool b)
4839 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4840 // they implement an implicit conversion to any of types above. This does
4841 // not apply when both operands are of same reference type
4843 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4844 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4849 // Now try lifted version of predefined operators
4851 if (no_arg_conv && !l.IsNullableType) {
4853 // Optimizes cases which won't match
4856 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4862 // The == and != operators permit one operand to be a value of a nullable
4863 // type and the other to be the null literal, even if no predefined or user-defined
4864 // operator (in unlifted or lifted form) exists for the operation.
4866 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4867 var lifted = new Nullable.LiftedBinaryOperator (this);
4869 lifted.Right = right;
4870 return lifted.Resolve (ec);
4875 // bool operator != (object a, object b)
4876 // bool operator == (object a, object b)
4878 // An explicit reference conversion exists from the
4879 // type of either operand to the type of the other operand.
4882 // Optimize common path
4884 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4887 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4888 !Convert.ExplicitReferenceConversionExists (r, l))
4891 // Reject allowed explicit conversions like int->object
4892 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4895 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4896 ec.Report.Warning (253, 2, loc,
4897 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4898 l.GetSignatureForError ());
4900 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4901 ec.Report.Warning (252, 2, loc,
4902 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4903 r.GetSignatureForError ());
4909 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4912 // bool operator == (void* x, void* y);
4913 // bool operator != (void* x, void* y);
4914 // bool operator < (void* x, void* y);
4915 // bool operator > (void* x, void* y);
4916 // bool operator <= (void* x, void* y);
4917 // bool operator >= (void* x, void* y);
4919 if ((oper & Operator.ComparisonMask) != 0) {
4922 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4929 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4935 type = ec.BuiltinTypes.Bool;
4939 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4943 // Build-in operators method overloading
4945 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4947 PredefinedOperator best_operator = null;
4948 TypeSpec l = left.Type;
4949 TypeSpec r = right.Type;
4950 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4952 foreach (PredefinedOperator po in operators) {
4953 if ((po.OperatorsMask & oper_mask) == 0)
4956 if (primitives_only) {
4957 if (!po.IsPrimitiveApplicable (l, r))
4960 if (!po.IsApplicable (ec, left, right))
4964 if (best_operator == null) {
4966 if (primitives_only)
4972 best_operator = po.ResolveBetterOperator (ec, best_operator);
4974 if (best_operator == null) {
4975 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4976 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4983 if (best_operator == null)
4986 return best_operator.ConvertResult (ec, this);
4990 // Optimize & constant expressions with 0 value
4992 Expression OptimizeAndOperation (Expression expr)
4994 Constant rc = right as Constant;
4995 Constant lc = left as Constant;
4996 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4998 // The result is a constant with side-effect
5000 Constant side_effect = rc == null ?
5001 new SideEffectConstant (lc, right, loc) :
5002 new SideEffectConstant (rc, left, loc);
5004 return ReducedExpression.Create (side_effect, expr);
5011 // Value types can be compared with the null literal because of the lifting
5012 // language rules. However the result is always true or false.
5014 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5016 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5017 type = rc.BuiltinTypes.Bool;
5021 // FIXME: Handle side effect constants
5022 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5024 if ((Oper & Operator.EqualityMask) != 0) {
5025 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5026 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5028 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5029 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5036 // Performs user-operator overloading
5038 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5040 Expression oper_expr;
5042 var op = ConvertBinaryToUserOperator (oper);
5044 if (l.IsNullableType)
5045 l = Nullable.NullableInfo.GetUnderlyingType (l);
5047 if (r.IsNullableType)
5048 r = Nullable.NullableInfo.GetUnderlyingType (r);
5050 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5051 IList<MemberSpec> right_operators = null;
5054 right_operators = MemberCache.GetUserOperator (r, op, false);
5055 if (right_operators == null && left_operators == null)
5057 } else if (left_operators == null) {
5061 Arguments args = new Arguments (2);
5062 Argument larg = new Argument (left);
5064 Argument rarg = new Argument (right);
5068 // User-defined operator implementations always take precedence
5069 // over predefined operator implementations
5071 if (left_operators != null && right_operators != null) {
5072 left_operators = CombineUserOperators (left_operators, right_operators);
5073 } else if (right_operators != null) {
5074 left_operators = right_operators;
5077 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5078 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5080 var res = new OverloadResolver (left_operators, restr, loc);
5082 var oper_method = res.ResolveOperator (rc, ref args);
5083 if (oper_method == null) {
5085 // Logical && and || cannot be lifted
5087 if ((oper & Operator.LogicalMask) != 0)
5091 // Apply lifted user operators only for liftable types. Implicit conversion
5092 // to nullable types is not allowed
5094 if (!IsLiftedOperatorApplicable ())
5097 // TODO: Cache the result in module container
5098 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5099 if (lifted_methods == null)
5102 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5104 oper_method = res.ResolveOperator (rc, ref args);
5105 if (oper_method == null)
5108 MethodSpec best_original = null;
5109 foreach (MethodSpec ms in left_operators) {
5110 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5116 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5118 // Expression trees use lifted notation in this case
5120 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5121 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5124 var ptypes = best_original.Parameters.Types;
5126 if (left.IsNull || right.IsNull) {
5128 // The lifted operator produces a null value if one or both operands are null
5130 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5131 type = oper_method.ReturnType;
5132 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5136 // The lifted operator produces the value false if one or both operands are null for
5137 // relational operators.
5139 if ((oper & Operator.RelationalMask) != 0) {
5141 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5142 // because return type is actually bool
5144 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5147 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5148 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5152 type = oper_method.ReturnType;
5153 var lifted = new Nullable.LiftedBinaryOperator (this);
5154 lifted.UserOperator = best_original;
5156 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5157 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5160 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5161 lifted.UnwrapRight = new Nullable.Unwrap (right);
5164 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5165 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5167 return lifted.Resolve (rc);
5170 if ((oper & Operator.LogicalMask) != 0) {
5171 // TODO: CreateExpressionTree is allocated every time
5172 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5173 oper == Operator.LogicalAnd, loc).Resolve (rc);
5175 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5178 this.left = larg.Expr;
5179 this.right = rarg.Expr;
5184 bool IsLiftedOperatorApplicable ()
5186 if (left.Type.IsNullableType) {
5187 if ((oper & Operator.EqualityMask) != 0)
5188 return !right.IsNull;
5193 if (right.Type.IsNullableType) {
5194 if ((oper & Operator.EqualityMask) != 0)
5195 return !left.IsNull;
5200 if (TypeSpec.IsValueType (left.Type))
5201 return right.IsNull;
5203 if (TypeSpec.IsValueType (right.Type))
5209 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5211 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5212 if (nullable_type == null)
5216 // Lifted operators permit predefined and user-defined operators that operate
5217 // on non-nullable value types to also be used with nullable forms of those types.
5218 // Lifted operators are constructed from predefined and user-defined operators
5219 // that meet certain requirements
5221 List<MemberSpec> lifted = null;
5222 foreach (MethodSpec oper in operators) {
5224 if ((Oper & Operator.ComparisonMask) != 0) {
5226 // Result type must be of type bool for lifted comparison operators
5228 rt = oper.ReturnType;
5229 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5232 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5238 var ptypes = oper.Parameters.Types;
5239 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5243 // LAMESPEC: I am not sure why but for equality operators to be lifted
5244 // both types have to match
5246 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5250 lifted = new List<MemberSpec> ();
5253 // The lifted form is constructed by adding a single ? modifier to each operand and
5254 // result type except for comparison operators where return type is bool
5257 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5259 var parameters = ParametersCompiled.CreateFullyResolved (
5260 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5261 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5263 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5264 rt, parameters, oper.Modifiers);
5266 lifted.Add (lifted_op);
5273 // Merge two sets of user operators into one, they are mostly distinguish
5274 // except when they share base type and it contains an operator
5276 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5278 var combined = new List<MemberSpec> (left.Count + right.Count);
5279 combined.AddRange (left);
5280 foreach (var r in right) {
5282 foreach (var l in left) {
5283 if (l.DeclaringType == r.DeclaringType) {
5296 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5298 if (c is IntegralConstant || c is CharConstant) {
5300 c.ConvertExplicitly (true, type);
5301 } catch (OverflowException) {
5302 ec.Report.Warning (652, 2, loc,
5303 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5304 type.GetSignatureForError ());
5310 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5311 /// context of a conditional bool expression. This function will return
5312 /// false if it is was possible to use EmitBranchable, or true if it was.
5314 /// The expression's code is generated, and we will generate a branch to `target'
5315 /// if the resulting expression value is equal to isTrue
5317 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5319 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5320 left = left.EmitToField (ec);
5322 if ((oper & Operator.LogicalMask) == 0) {
5323 right = right.EmitToField (ec);
5328 // This is more complicated than it looks, but its just to avoid
5329 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5330 // but on top of that we want for == and != to use a special path
5331 // if we are comparing against null
5333 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5334 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5337 // put the constant on the rhs, for simplicity
5339 if (left is Constant) {
5340 Expression swap = right;
5346 // brtrue/brfalse works with native int only
5348 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5349 left.EmitBranchable (ec, target, my_on_true);
5352 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5353 // right is a boolean, and it's not 'false' => it is 'true'
5354 left.EmitBranchable (ec, target, !my_on_true);
5358 } else if (oper == Operator.LogicalAnd) {
5361 Label tests_end = ec.DefineLabel ();
5363 left.EmitBranchable (ec, tests_end, false);
5364 right.EmitBranchable (ec, target, true);
5365 ec.MarkLabel (tests_end);
5368 // This optimizes code like this
5369 // if (true && i > 4)
5371 if (!(left is Constant))
5372 left.EmitBranchable (ec, target, false);
5374 if (!(right is Constant))
5375 right.EmitBranchable (ec, target, false);
5380 } else if (oper == Operator.LogicalOr){
5382 left.EmitBranchable (ec, target, true);
5383 right.EmitBranchable (ec, target, true);
5386 Label tests_end = ec.DefineLabel ();
5387 left.EmitBranchable (ec, tests_end, true);
5388 right.EmitBranchable (ec, target, false);
5389 ec.MarkLabel (tests_end);
5394 } else if ((oper & Operator.ComparisonMask) == 0) {
5395 base.EmitBranchable (ec, target, on_true);
5402 TypeSpec t = left.Type;
5403 bool is_float = IsFloat (t);
5404 bool is_unsigned = is_float || IsUnsigned (t);
5407 case Operator.Equality:
5409 ec.Emit (OpCodes.Beq, target);
5411 ec.Emit (OpCodes.Bne_Un, target);
5414 case Operator.Inequality:
5416 ec.Emit (OpCodes.Bne_Un, target);
5418 ec.Emit (OpCodes.Beq, target);
5421 case Operator.LessThan:
5423 if (is_unsigned && !is_float)
5424 ec.Emit (OpCodes.Blt_Un, target);
5426 ec.Emit (OpCodes.Blt, target);
5429 ec.Emit (OpCodes.Bge_Un, target);
5431 ec.Emit (OpCodes.Bge, target);
5434 case Operator.GreaterThan:
5436 if (is_unsigned && !is_float)
5437 ec.Emit (OpCodes.Bgt_Un, target);
5439 ec.Emit (OpCodes.Bgt, target);
5442 ec.Emit (OpCodes.Ble_Un, target);
5444 ec.Emit (OpCodes.Ble, target);
5447 case Operator.LessThanOrEqual:
5449 if (is_unsigned && !is_float)
5450 ec.Emit (OpCodes.Ble_Un, target);
5452 ec.Emit (OpCodes.Ble, target);
5455 ec.Emit (OpCodes.Bgt_Un, target);
5457 ec.Emit (OpCodes.Bgt, target);
5461 case Operator.GreaterThanOrEqual:
5463 if (is_unsigned && !is_float)
5464 ec.Emit (OpCodes.Bge_Un, target);
5466 ec.Emit (OpCodes.Bge, target);
5469 ec.Emit (OpCodes.Blt_Un, target);
5471 ec.Emit (OpCodes.Blt, target);
5474 throw new InternalErrorException (oper.ToString ());
5478 public override void Emit (EmitContext ec)
5480 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5481 left = left.EmitToField (ec);
5483 if ((oper & Operator.LogicalMask) == 0) {
5484 right = right.EmitToField (ec);
5489 // Handle short-circuit operators differently
5492 if ((oper & Operator.LogicalMask) != 0) {
5493 Label load_result = ec.DefineLabel ();
5494 Label end = ec.DefineLabel ();
5496 bool is_or = oper == Operator.LogicalOr;
5497 left.EmitBranchable (ec, load_result, is_or);
5499 ec.Emit (OpCodes.Br_S, end);
5501 ec.MarkLabel (load_result);
5502 ec.EmitInt (is_or ? 1 : 0);
5508 // Optimize zero-based operations which cannot be optimized at expression level
5510 if (oper == Operator.Subtraction) {
5511 var lc = left as IntegralConstant;
5512 if (lc != null && lc.IsDefaultValue) {
5514 ec.Emit (OpCodes.Neg);
5519 EmitOperator (ec, left, right);
5522 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5527 EmitOperatorOpcode (ec, oper, left.Type, right);
5530 // Emit result enumerable conversion this way because it's quite complicated get it
5531 // to resolved tree because expression tree cannot see it.
5533 if (enum_conversion != 0)
5534 ConvCast.Emit (ec, enum_conversion);
5537 public override void EmitSideEffect (EmitContext ec)
5539 if ((oper & Operator.LogicalMask) != 0 ||
5540 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5541 base.EmitSideEffect (ec);
5543 left.EmitSideEffect (ec);
5544 right.EmitSideEffect (ec);
5548 public override Expression EmitToField (EmitContext ec)
5550 if ((oper & Operator.LogicalMask) == 0) {
5551 var await_expr = left as Await;
5552 if (await_expr != null && right.IsSideEffectFree) {
5553 await_expr.Statement.EmitPrologue (ec);
5554 left = await_expr.Statement.GetResultExpression (ec);
5558 await_expr = right as Await;
5559 if (await_expr != null && left.IsSideEffectFree) {
5560 await_expr.Statement.EmitPrologue (ec);
5561 right = await_expr.Statement.GetResultExpression (ec);
5566 return base.EmitToField (ec);
5569 protected override void CloneTo (CloneContext clonectx, Expression t)
5571 Binary target = (Binary) t;
5573 target.left = left.Clone (clonectx);
5574 target.right = right.Clone (clonectx);
5577 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5579 Arguments binder_args = new Arguments (4);
5581 MemberAccess sle = new MemberAccess (new MemberAccess (
5582 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5584 CSharpBinderFlags flags = 0;
5585 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5586 flags = CSharpBinderFlags.CheckedContext;
5588 if ((oper & Operator.LogicalMask) != 0)
5589 flags |= CSharpBinderFlags.BinaryOperationLogical;
5591 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5592 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5593 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5594 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5596 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5599 public override Expression CreateExpressionTree (ResolveContext ec)
5601 return CreateExpressionTree (ec, null);
5604 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5607 bool lift_arg = false;
5610 case Operator.Addition:
5611 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5612 method_name = "AddChecked";
5614 method_name = "Add";
5616 case Operator.BitwiseAnd:
5617 method_name = "And";
5619 case Operator.BitwiseOr:
5622 case Operator.Division:
5623 method_name = "Divide";
5625 case Operator.Equality:
5626 method_name = "Equal";
5629 case Operator.ExclusiveOr:
5630 method_name = "ExclusiveOr";
5632 case Operator.GreaterThan:
5633 method_name = "GreaterThan";
5636 case Operator.GreaterThanOrEqual:
5637 method_name = "GreaterThanOrEqual";
5640 case Operator.Inequality:
5641 method_name = "NotEqual";
5644 case Operator.LeftShift:
5645 method_name = "LeftShift";
5647 case Operator.LessThan:
5648 method_name = "LessThan";
5651 case Operator.LessThanOrEqual:
5652 method_name = "LessThanOrEqual";
5655 case Operator.LogicalAnd:
5656 method_name = "AndAlso";
5658 case Operator.LogicalOr:
5659 method_name = "OrElse";
5661 case Operator.Modulus:
5662 method_name = "Modulo";
5664 case Operator.Multiply:
5665 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5666 method_name = "MultiplyChecked";
5668 method_name = "Multiply";
5670 case Operator.RightShift:
5671 method_name = "RightShift";
5673 case Operator.Subtraction:
5674 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5675 method_name = "SubtractChecked";
5677 method_name = "Subtract";
5681 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5684 Arguments args = new Arguments (2);
5685 args.Add (new Argument (left.CreateExpressionTree (ec)));
5686 args.Add (new Argument (right.CreateExpressionTree (ec)));
5687 if (method != null) {
5689 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5691 args.Add (new Argument (method));
5694 return CreateExpressionFactoryCall (ec, method_name, args);
5697 public override object Accept (StructuralVisitor visitor)
5699 return visitor.Visit (this);
5705 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5706 // b, c, d... may be strings or objects.
5708 public class StringConcat : Expression
5710 Arguments arguments;
5712 StringConcat (Location loc)
5715 arguments = new Arguments (2);
5718 public override bool ContainsEmitWithAwait ()
5720 return arguments.ContainsEmitWithAwait ();
5723 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5725 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5726 throw new ArgumentException ();
5728 var s = new StringConcat (loc);
5729 s.type = rc.BuiltinTypes.String;
5730 s.eclass = ExprClass.Value;
5732 s.Append (rc, left);
5733 s.Append (rc, right);
5737 public override Expression CreateExpressionTree (ResolveContext ec)
5739 Argument arg = arguments [0];
5740 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5744 // Creates nested calls tree from an array of arguments used for IL emit
5746 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5748 Arguments concat_args = new Arguments (2);
5749 Arguments add_args = new Arguments (3);
5751 concat_args.Add (left);
5752 add_args.Add (new Argument (left_etree));
5754 concat_args.Add (arguments [pos]);
5755 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5757 var methods = GetConcatMethodCandidates ();
5758 if (methods == null)
5761 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5762 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5766 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5768 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5769 if (++pos == arguments.Count)
5772 left = new Argument (new EmptyExpression (method.ReturnType));
5773 return CreateExpressionAddCall (ec, left, expr, pos);
5776 protected override Expression DoResolve (ResolveContext ec)
5781 void Append (ResolveContext rc, Expression operand)
5786 StringConstant sc = operand as StringConstant;
5788 if (arguments.Count != 0) {
5789 Argument last_argument = arguments [arguments.Count - 1];
5790 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5791 if (last_expr_constant != null) {
5792 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5798 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5800 StringConcat concat_oper = operand as StringConcat;
5801 if (concat_oper != null) {
5802 arguments.AddRange (concat_oper.arguments);
5807 arguments.Add (new Argument (operand));
5810 IList<MemberSpec> GetConcatMethodCandidates ()
5812 return MemberCache.FindMembers (type, "Concat", true);
5815 public override void Emit (EmitContext ec)
5817 // Optimize by removing any extra null arguments, they are no-op
5818 for (int i = 0; i < arguments.Count; ++i) {
5819 if (arguments[i].Expr is NullConstant)
5820 arguments.RemoveAt (i--);
5823 var members = GetConcatMethodCandidates ();
5824 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5825 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5826 if (method != null) {
5827 var call = new CallEmitter ();
5828 call.EmitPredefined (ec, method, arguments, false);
5832 public override void FlowAnalysis (FlowAnalysisContext fc)
5834 arguments.FlowAnalysis (fc);
5837 public override SLE.Expression MakeExpression (BuilderContext ctx)
5839 if (arguments.Count != 2)
5840 throw new NotImplementedException ("arguments.Count != 2");
5842 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5843 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5848 // User-defined conditional logical operator
5850 public class ConditionalLogicalOperator : UserOperatorCall
5852 readonly bool is_and;
5853 Expression oper_expr;
5855 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5856 : base (oper, arguments, expr_tree, loc)
5858 this.is_and = is_and;
5859 eclass = ExprClass.Unresolved;
5862 protected override Expression DoResolve (ResolveContext ec)
5864 AParametersCollection pd = oper.Parameters;
5865 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5866 ec.Report.Error (217, loc,
5867 "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",
5868 oper.GetSignatureForError ());
5872 Expression left_dup = new EmptyExpression (type);
5873 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5874 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5875 if (op_true == null || op_false == null) {
5876 ec.Report.Error (218, loc,
5877 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5878 type.GetSignatureForError (), oper.GetSignatureForError ());
5882 oper_expr = is_and ? op_false : op_true;
5883 eclass = ExprClass.Value;
5887 public override void Emit (EmitContext ec)
5889 Label end_target = ec.DefineLabel ();
5892 // Emit and duplicate left argument
5894 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5895 if (right_contains_await) {
5896 arguments[0] = arguments[0].EmitToField (ec, false);
5897 arguments[0].Expr.Emit (ec);
5899 arguments[0].Expr.Emit (ec);
5900 ec.Emit (OpCodes.Dup);
5901 arguments.RemoveAt (0);
5904 oper_expr.EmitBranchable (ec, end_target, true);
5908 if (right_contains_await) {
5910 // Special handling when right expression contains await and left argument
5911 // could not be left on stack before logical branch
5913 Label skip_left_load = ec.DefineLabel ();
5914 ec.Emit (OpCodes.Br_S, skip_left_load);
5915 ec.MarkLabel (end_target);
5916 arguments[0].Expr.Emit (ec);
5917 ec.MarkLabel (skip_left_load);
5919 ec.MarkLabel (end_target);
5924 public class PointerArithmetic : Expression {
5925 Expression left, right;
5926 readonly Binary.Operator op;
5929 // We assume that `l' is always a pointer
5931 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5940 public override bool ContainsEmitWithAwait ()
5942 throw new NotImplementedException ();
5945 public override Expression CreateExpressionTree (ResolveContext ec)
5947 Error_PointerInsideExpressionTree (ec);
5951 protected override Expression DoResolve (ResolveContext ec)
5953 eclass = ExprClass.Variable;
5955 var pc = left.Type as PointerContainer;
5956 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5957 Error_VoidPointerOperation (ec);
5964 public override void Emit (EmitContext ec)
5966 TypeSpec op_type = left.Type;
5968 // It must be either array or fixed buffer
5970 if (TypeManager.HasElementType (op_type)) {
5971 element = TypeManager.GetElementType (op_type);
5973 FieldExpr fe = left as FieldExpr;
5975 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5980 int size = BuiltinTypeSpec.GetSize(element);
5981 TypeSpec rtype = right.Type;
5983 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5985 // handle (pointer - pointer)
5989 ec.Emit (OpCodes.Sub);
5993 ec.Emit (OpCodes.Sizeof, element);
5996 ec.Emit (OpCodes.Div);
5998 ec.Emit (OpCodes.Conv_I8);
6001 // handle + and - on (pointer op int)
6003 Constant left_const = left as Constant;
6004 if (left_const != null) {
6006 // Optimize ((T*)null) pointer operations
6008 if (left_const.IsDefaultValue) {
6009 left = EmptyExpression.Null;
6017 var right_const = right as Constant;
6018 if (right_const != null) {
6020 // Optimize 0-based arithmetic
6022 if (right_const.IsDefaultValue)
6026 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6028 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6030 // TODO: Should be the checks resolve context sensitive?
6031 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6032 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6038 if (right_const == null) {
6039 switch (rtype.BuiltinType) {
6040 case BuiltinTypeSpec.Type.SByte:
6041 case BuiltinTypeSpec.Type.Byte:
6042 case BuiltinTypeSpec.Type.Short:
6043 case BuiltinTypeSpec.Type.UShort:
6044 case BuiltinTypeSpec.Type.Int:
6045 ec.Emit (OpCodes.Conv_I);
6047 case BuiltinTypeSpec.Type.UInt:
6048 ec.Emit (OpCodes.Conv_U);
6053 if (right_const == null && size != 1){
6055 ec.Emit (OpCodes.Sizeof, element);
6058 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6059 ec.Emit (OpCodes.Conv_I8);
6061 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6064 if (left_const == null) {
6065 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6066 ec.Emit (OpCodes.Conv_I);
6067 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6068 ec.Emit (OpCodes.Conv_U);
6070 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6077 // A boolean-expression is an expression that yields a result
6080 public class BooleanExpression : ShimExpression
6082 public BooleanExpression (Expression expr)
6085 this.loc = expr.Location;
6088 public override Expression CreateExpressionTree (ResolveContext ec)
6090 // TODO: We should emit IsTrue (v4) instead of direct user operator
6091 // call but that would break csc compatibility
6092 return base.CreateExpressionTree (ec);
6095 protected override Expression DoResolve (ResolveContext ec)
6097 // A boolean-expression is required to be of a type
6098 // that can be implicitly converted to bool or of
6099 // a type that implements operator true
6101 expr = expr.Resolve (ec);
6105 Assign ass = expr as Assign;
6106 if (ass != null && ass.Source is Constant) {
6107 ec.Report.Warning (665, 3, loc,
6108 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6111 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6114 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6115 Arguments args = new Arguments (1);
6116 args.Add (new Argument (expr));
6117 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6120 type = ec.BuiltinTypes.Bool;
6121 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6122 if (converted != null)
6126 // If no implicit conversion to bool exists, try using `operator true'
6128 converted = GetOperatorTrue (ec, expr, loc);
6129 if (converted == null) {
6130 expr.Error_ValueCannotBeConverted (ec, type, false);
6137 public override object Accept (StructuralVisitor visitor)
6139 return visitor.Visit (this);
6143 public class BooleanExpressionFalse : Unary
6145 public BooleanExpressionFalse (Expression expr)
6146 : base (Operator.LogicalNot, expr, expr.Location)
6150 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6152 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6157 /// Implements the ternary conditional operator (?:)
6159 public class Conditional : Expression {
6160 Expression expr, true_expr, false_expr;
6162 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6165 this.true_expr = true_expr;
6166 this.false_expr = false_expr;
6172 public Expression Expr {
6178 public Expression TrueExpr {
6184 public Expression FalseExpr {
6192 public override bool ContainsEmitWithAwait ()
6194 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6197 public override Expression CreateExpressionTree (ResolveContext ec)
6199 Arguments args = new Arguments (3);
6200 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6201 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6202 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6203 return CreateExpressionFactoryCall (ec, "Condition", args);
6206 protected override Expression DoResolve (ResolveContext ec)
6208 expr = expr.Resolve (ec);
6209 true_expr = true_expr.Resolve (ec);
6210 false_expr = false_expr.Resolve (ec);
6212 if (true_expr == null || false_expr == null || expr == null)
6215 eclass = ExprClass.Value;
6216 TypeSpec true_type = true_expr.Type;
6217 TypeSpec false_type = false_expr.Type;
6221 // First, if an implicit conversion exists from true_expr
6222 // to false_expr, then the result type is of type false_expr.Type
6224 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6225 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6226 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6228 // Check if both can convert implicitly to each other's type
6232 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6233 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6235 // LAMESPEC: There seems to be hardcoded promotition to int type when
6236 // both sides are numeric constants and one side is int constant and
6237 // other side is numeric constant convertible to int.
6239 // var res = condition ? (short)1 : 1;
6241 // Type of res is int even if according to the spec the conversion is
6242 // ambiguous because 1 literal can be converted to short.
6244 if (conv_false_expr != null) {
6245 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6247 conv_false_expr = null;
6248 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6249 conv_false_expr = null;
6253 if (conv_false_expr != null) {
6254 ec.Report.Error (172, true_expr.Location,
6255 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6256 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6261 if (true_expr.Type != type)
6262 true_expr = EmptyCast.Create (true_expr, type);
6263 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6266 if (false_type != InternalType.ErrorType) {
6267 ec.Report.Error (173, true_expr.Location,
6268 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6269 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6275 Constant c = expr as Constant;
6277 bool is_false = c.IsDefaultValue;
6280 // Don't issue the warning for constant expressions
6282 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6283 // CSC: Missing warning
6284 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6287 return ReducedExpression.Create (
6288 is_false ? false_expr : true_expr, this,
6289 false_expr is Constant && true_expr is Constant).Resolve (ec);
6295 public override void Emit (EmitContext ec)
6297 Label false_target = ec.DefineLabel ();
6298 Label end_target = ec.DefineLabel ();
6300 expr.EmitBranchable (ec, false_target, false);
6301 true_expr.Emit (ec);
6304 // Verifier doesn't support interface merging. When there are two types on
6305 // the stack without common type hint and the common type is an interface.
6306 // Use temporary local to give verifier hint on what type to unify the stack
6308 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6309 var temp = ec.GetTemporaryLocal (type);
6310 ec.Emit (OpCodes.Stloc, temp);
6311 ec.Emit (OpCodes.Ldloc, temp);
6312 ec.FreeTemporaryLocal (temp, type);
6315 ec.Emit (OpCodes.Br, end_target);
6316 ec.MarkLabel (false_target);
6317 false_expr.Emit (ec);
6318 ec.MarkLabel (end_target);
6321 public override void FlowAnalysis (FlowAnalysisContext fc)
6323 expr.FlowAnalysisConditional (fc);
6324 var expr_true = fc.DefiniteAssignmentOnTrue;
6325 var expr_false = fc.DefiniteAssignmentOnFalse;
6327 fc.BranchDefiniteAssignment (expr_true);
6328 true_expr.FlowAnalysis (fc);
6329 var true_fc = fc.DefiniteAssignment;
6331 fc.BranchDefiniteAssignment (expr_false);
6332 false_expr.FlowAnalysis (fc);
6334 fc.DefiniteAssignment &= true_fc;
6337 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6339 expr.FlowAnalysisConditional (fc);
6340 var expr_true = fc.DefiniteAssignmentOnTrue;
6341 var expr_false = fc.DefiniteAssignmentOnFalse;
6343 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6344 true_expr.FlowAnalysisConditional (fc);
6345 var true_fc = fc.DefiniteAssignment;
6346 var true_da_true = fc.DefiniteAssignmentOnTrue;
6347 var true_da_false = fc.DefiniteAssignmentOnFalse;
6349 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6350 false_expr.FlowAnalysisConditional (fc);
6352 fc.DefiniteAssignment &= true_fc;
6353 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6354 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6357 protected override void CloneTo (CloneContext clonectx, Expression t)
6359 Conditional target = (Conditional) t;
6361 target.expr = expr.Clone (clonectx);
6362 target.true_expr = true_expr.Clone (clonectx);
6363 target.false_expr = false_expr.Clone (clonectx);
6367 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6369 LocalTemporary temp;
6372 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6373 public abstract void SetHasAddressTaken ();
6375 public abstract bool IsLockedByStatement { get; set; }
6377 public abstract bool IsFixed { get; }
6378 public abstract bool IsRef { get; }
6379 public abstract string Name { get; }
6382 // Variable IL data, it has to be protected to encapsulate hoisted variables
6384 protected abstract ILocalVariable Variable { get; }
6387 // Variable flow-analysis data
6389 public abstract VariableInfo VariableInfo { get; }
6392 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6394 HoistedVariable hv = GetHoistedVariable (ec);
6396 hv.AddressOf (ec, mode);
6400 Variable.EmitAddressOf (ec);
6403 public override bool ContainsEmitWithAwait ()
6408 public override Expression CreateExpressionTree (ResolveContext ec)
6410 HoistedVariable hv = GetHoistedVariable (ec);
6412 return hv.CreateExpressionTree ();
6414 Arguments arg = new Arguments (1);
6415 arg.Add (new Argument (this));
6416 return CreateExpressionFactoryCall (ec, "Constant", arg);
6419 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6421 if (IsLockedByStatement) {
6422 rc.Report.Warning (728, 2, loc,
6423 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6430 public override void Emit (EmitContext ec)
6435 public override void EmitSideEffect (EmitContext ec)
6441 // This method is used by parameters that are references, that are
6442 // being passed as references: we only want to pass the pointer (that
6443 // is already stored in the parameter, not the address of the pointer,
6444 // and not the value of the variable).
6446 public void EmitLoad (EmitContext ec)
6451 public void Emit (EmitContext ec, bool leave_copy)
6453 HoistedVariable hv = GetHoistedVariable (ec);
6455 hv.Emit (ec, leave_copy);
6463 // If we are a reference, we loaded on the stack a pointer
6464 // Now lets load the real value
6466 ec.EmitLoadFromPtr (type);
6470 ec.Emit (OpCodes.Dup);
6473 temp = new LocalTemporary (Type);
6479 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6480 bool prepare_for_load)
6482 HoistedVariable hv = GetHoistedVariable (ec);
6484 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6488 New n_source = source as New;
6489 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6490 if (!n_source.Emit (ec, this)) {
6494 ec.EmitLoadFromPtr (type);
6506 ec.Emit (OpCodes.Dup);
6508 temp = new LocalTemporary (Type);
6514 ec.EmitStoreFromPtr (type);
6516 Variable.EmitAssign (ec);
6524 public override Expression EmitToField (EmitContext ec)
6526 HoistedVariable hv = GetHoistedVariable (ec);
6528 return hv.EmitToField (ec);
6531 return base.EmitToField (ec);
6534 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6536 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6539 public HoistedVariable GetHoistedVariable (EmitContext ec)
6541 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6544 public override string GetSignatureForError ()
6549 public bool IsHoisted {
6550 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6555 // Resolved reference to a local variable
6557 public class LocalVariableReference : VariableReference
6559 public LocalVariable local_info;
6561 public LocalVariableReference (LocalVariable li, Location l)
6563 this.local_info = li;
6567 public override VariableInfo VariableInfo {
6568 get { return local_info.VariableInfo; }
6571 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6573 return local_info.HoistedVariant;
6579 // A local variable is always fixed
6581 public override bool IsFixed {
6587 public override bool IsLockedByStatement {
6589 return local_info.IsLocked;
6592 local_info.IsLocked = value;
6596 public override bool IsRef {
6597 get { return false; }
6600 public override string Name {
6601 get { return local_info.Name; }
6606 public override void FlowAnalysis (FlowAnalysisContext fc)
6608 VariableInfo variable_info = VariableInfo;
6609 if (variable_info == null)
6612 if (fc.IsDefinitelyAssigned (variable_info))
6615 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6616 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6619 public override void SetHasAddressTaken ()
6621 local_info.SetHasAddressTaken ();
6624 void DoResolveBase (ResolveContext ec)
6626 eclass = ExprClass.Variable;
6627 type = local_info.Type;
6630 // If we are referencing a variable from the external block
6631 // flag it for capturing
6633 if (ec.MustCaptureVariable (local_info)) {
6634 if (local_info.AddressTaken) {
6635 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6636 } else if (local_info.IsFixed) {
6637 ec.Report.Error (1764, loc,
6638 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6639 GetSignatureForError ());
6642 if (ec.IsVariableCapturingRequired) {
6643 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6644 storey.CaptureLocalVariable (ec, local_info);
6649 protected override Expression DoResolve (ResolveContext ec)
6651 local_info.SetIsUsed ();
6655 if (local_info.Type == InternalType.VarOutType) {
6656 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6657 GetSignatureForError ());
6659 type = InternalType.ErrorType;
6665 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6668 // Don't be too pedantic when variable is used as out param or for some broken code
6669 // which uses property/indexer access to run some initialization
6671 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6672 local_info.SetIsUsed ();
6674 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6675 if (rhs == EmptyExpression.LValueMemberAccess) {
6676 // CS1654 already reported
6680 if (rhs == EmptyExpression.OutAccess) {
6681 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6682 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6683 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6684 } else if (rhs == EmptyExpression.UnaryAddress) {
6685 code = 459; msg = "Cannot take the address of {1} `{0}'";
6687 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6689 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6693 if (eclass == ExprClass.Unresolved)
6696 return base.DoResolveLValue (ec, rhs);
6699 public override int GetHashCode ()
6701 return local_info.GetHashCode ();
6704 public override bool Equals (object obj)
6706 LocalVariableReference lvr = obj as LocalVariableReference;
6710 return local_info == lvr.local_info;
6713 protected override ILocalVariable Variable {
6714 get { return local_info; }
6717 public override string ToString ()
6719 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6722 protected override void CloneTo (CloneContext clonectx, Expression t)
6729 /// This represents a reference to a parameter in the intermediate
6732 public class ParameterReference : VariableReference
6734 protected ParametersBlock.ParameterInfo pi;
6736 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6744 public override bool IsLockedByStatement {
6749 pi.IsLocked = value;
6753 public override bool IsRef {
6754 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6757 bool HasOutModifier {
6758 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6761 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6763 return pi.Parameter.HoistedVariant;
6767 // A ref or out parameter is classified as a moveable variable, even
6768 // if the argument given for the parameter is a fixed variable
6770 public override bool IsFixed {
6771 get { return !IsRef; }
6774 public override string Name {
6775 get { return Parameter.Name; }
6778 public Parameter Parameter {
6779 get { return pi.Parameter; }
6782 public override VariableInfo VariableInfo {
6783 get { return pi.VariableInfo; }
6786 protected override ILocalVariable Variable {
6787 get { return Parameter; }
6792 public override void AddressOf (EmitContext ec, AddressOp mode)
6795 // ParameterReferences might already be a reference
6802 base.AddressOf (ec, mode);
6805 public override void SetHasAddressTaken ()
6807 Parameter.HasAddressTaken = true;
6810 bool DoResolveBase (ResolveContext ec)
6812 if (eclass != ExprClass.Unresolved)
6815 type = pi.ParameterType;
6816 eclass = ExprClass.Variable;
6819 // If we are referencing a parameter from the external block
6820 // flag it for capturing
6822 if (ec.MustCaptureVariable (pi)) {
6823 if (Parameter.HasAddressTaken)
6824 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6827 ec.Report.Error (1628, loc,
6828 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6829 Name, ec.CurrentAnonymousMethod.ContainerType);
6832 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6833 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6834 storey.CaptureParameter (ec, pi, this);
6841 public override int GetHashCode ()
6843 return Name.GetHashCode ();
6846 public override bool Equals (object obj)
6848 ParameterReference pr = obj as ParameterReference;
6852 return Name == pr.Name;
6855 protected override void CloneTo (CloneContext clonectx, Expression target)
6861 public override Expression CreateExpressionTree (ResolveContext ec)
6863 HoistedVariable hv = GetHoistedVariable (ec);
6865 return hv.CreateExpressionTree ();
6867 return Parameter.ExpressionTreeVariableReference ();
6870 protected override Expression DoResolve (ResolveContext ec)
6872 if (!DoResolveBase (ec))
6878 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6880 if (!DoResolveBase (ec))
6883 if (Parameter.HoistedVariant != null)
6884 Parameter.HoistedVariant.IsAssigned = true;
6886 return base.DoResolveLValue (ec, right_side);
6889 public override void FlowAnalysis (FlowAnalysisContext fc)
6891 VariableInfo variable_info = VariableInfo;
6892 if (variable_info == null)
6895 if (fc.IsDefinitelyAssigned (variable_info))
6898 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6899 fc.SetVariableAssigned (variable_info);
6904 /// Invocation of methods or delegates.
6906 public class Invocation : ExpressionStatement
6908 public class Predefined : Invocation
6910 public Predefined (MethodGroupExpr expr, Arguments arguments)
6911 : base (expr, arguments)
6916 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6918 mg.BestCandidate.CheckObsoleteness (rc, loc);
6924 protected Arguments arguments;
6925 protected Expression expr;
6926 protected MethodGroupExpr mg;
6927 bool conditional_access_receiver;
6929 public Invocation (Expression expr, Arguments arguments)
6932 this.arguments = arguments;
6934 loc = expr.Location;
6939 public Arguments Arguments {
6945 public Expression Exp {
6951 public MethodGroupExpr MethodGroup {
6957 public override Location StartLocation {
6959 return expr.StartLocation;
6965 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6967 if (MethodGroup == null)
6970 var candidate = MethodGroup.BestCandidate;
6971 if (candidate == null || !(candidate.IsStatic || Exp is This))
6974 var args_count = arguments == null ? 0 : arguments.Count;
6975 if (args_count != body.Parameters.Count)
6978 var lambda_parameters = body.Block.Parameters.FixedParameters;
6979 for (int i = 0; i < args_count; ++i) {
6980 var pr = arguments[i].Expr as ParameterReference;
6984 if (lambda_parameters[i] != pr.Parameter)
6987 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6991 var emg = MethodGroup as ExtensionMethodGroupExpr;
6993 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6994 if (candidate.IsGeneric) {
6995 var targs = new TypeExpression [candidate.Arity];
6996 for (int i = 0; i < targs.Length; ++i) {
6997 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7000 mg.SetTypeArguments (null, new TypeArguments (targs));
7009 protected override void CloneTo (CloneContext clonectx, Expression t)
7011 Invocation target = (Invocation) t;
7013 if (arguments != null)
7014 target.arguments = arguments.Clone (clonectx);
7016 target.expr = expr.Clone (clonectx);
7019 public override bool ContainsEmitWithAwait ()
7021 if (arguments != null && arguments.ContainsEmitWithAwait ())
7024 return mg.ContainsEmitWithAwait ();
7027 public override Expression CreateExpressionTree (ResolveContext ec)
7029 Expression instance = mg.IsInstance ?
7030 mg.InstanceExpression.CreateExpressionTree (ec) :
7031 new NullLiteral (loc);
7033 var args = Arguments.CreateForExpressionTree (ec, arguments,
7035 mg.CreateExpressionTree (ec));
7037 return CreateExpressionFactoryCall (ec, "Call", args);
7040 void ResolveConditionalAccessReceiver (ResolveContext rc)
7042 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7043 conditional_access_receiver = true;
7047 bool statement_resolve;
7048 public override ExpressionStatement ResolveStatement (BlockContext bc)
7050 statement_resolve = true;
7051 var es = base.ResolveStatement (bc);
7052 statement_resolve = false;
7057 protected override Expression DoResolve (ResolveContext rc)
7059 ResolveConditionalAccessReceiver (rc);
7060 return DoResolveInvocation (rc);
7063 Expression DoResolveInvocation (ResolveContext ec)
7065 Expression member_expr;
7066 var atn = expr as ATypeNameExpression;
7068 var flags = default (ResolveContext.FlagsHandle);
7069 if (conditional_access_receiver)
7070 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7073 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7074 if (member_expr != null) {
7075 var name_of = member_expr as NameOf;
7076 if (name_of != null) {
7077 return name_of.ResolveOverload (ec, arguments);
7080 member_expr = member_expr.Resolve (ec);
7083 member_expr = expr.Resolve (ec);
7086 if (conditional_access_receiver)
7089 if (member_expr == null)
7093 // Next, evaluate all the expressions in the argument list
7095 bool dynamic_arg = false;
7096 if (arguments != null) {
7097 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7098 arguments.Resolve (ec, out dynamic_arg);
7102 TypeSpec expr_type = member_expr.Type;
7103 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7104 return DoResolveDynamic (ec, member_expr);
7106 mg = member_expr as MethodGroupExpr;
7107 Expression invoke = null;
7110 if (expr_type != null && expr_type.IsDelegate) {
7111 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7112 invoke = invoke.Resolve (ec);
7113 if (invoke == null || !dynamic_arg)
7116 if (member_expr is RuntimeValueExpression) {
7117 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7118 member_expr.Type.GetSignatureForError ());
7122 MemberExpr me = member_expr as MemberExpr;
7124 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7128 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7129 member_expr.GetSignatureForError ());
7134 if (invoke == null) {
7135 mg = DoResolveOverload (ec);
7141 return DoResolveDynamic (ec, member_expr);
7143 var method = mg.BestCandidate;
7144 type = mg.BestCandidateReturnType;
7145 if (conditional_access_receiver && !statement_resolve)
7146 type = LiftMemberType (ec, type);
7148 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7150 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7152 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7156 IsSpecialMethodInvocation (ec, method, loc);
7158 eclass = ExprClass.Value;
7162 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7165 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7167 args = dmb.Arguments;
7168 if (arguments != null)
7169 args.AddRange (arguments);
7170 } else if (mg == null) {
7171 if (arguments == null)
7172 args = new Arguments (1);
7176 args.Insert (0, new Argument (memberExpr));
7180 ec.Report.Error (1971, loc,
7181 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7186 if (arguments == null)
7187 args = new Arguments (1);
7191 MemberAccess ma = expr as MemberAccess;
7193 var inst = mg.InstanceExpression;
7194 var left_type = inst as TypeExpr;
7195 if (left_type != null) {
7196 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7197 } else if (inst != null) {
7199 // Any value type has to be pass as by-ref to get back the same
7200 // instance on which the member was called
7202 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7203 Argument.AType.Ref : Argument.AType.None;
7204 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7206 } else { // is SimpleName
7207 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7208 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7210 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7215 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7218 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7220 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7223 public override void FlowAnalysis (FlowAnalysisContext fc)
7225 if (mg.IsConditionallyExcluded)
7228 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7230 mg.FlowAnalysis (fc);
7232 if (arguments != null)
7233 arguments.FlowAnalysis (fc);
7235 if (conditional_access_receiver)
7236 fc.DefiniteAssignment = da;
7239 public override string GetSignatureForError ()
7241 return mg.GetSignatureForError ();
7244 public override bool HasConditionalAccess ()
7246 return expr.HasConditionalAccess ();
7250 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7251 // or the type dynamic, then the member is invocable
7253 public static bool IsMemberInvocable (MemberSpec member)
7255 switch (member.Kind) {
7256 case MemberKind.Event:
7258 case MemberKind.Field:
7259 case MemberKind.Property:
7260 var m = member as IInterfaceMemberSpec;
7261 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7267 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7269 if (!method.IsReservedMethod)
7272 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7275 ec.Report.SymbolRelatedToPreviousError (method);
7276 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7277 method.GetSignatureForError ());
7282 public override void Emit (EmitContext ec)
7284 if (mg.IsConditionallyExcluded)
7287 if (conditional_access_receiver)
7288 mg.EmitCall (ec, arguments, type, false);
7290 mg.EmitCall (ec, arguments, false);
7293 public override void EmitStatement (EmitContext ec)
7295 if (mg.IsConditionallyExcluded)
7298 if (conditional_access_receiver)
7299 mg.EmitCall (ec, arguments, type, true);
7301 mg.EmitCall (ec, arguments, true);
7304 public override SLE.Expression MakeExpression (BuilderContext ctx)
7306 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7309 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7312 throw new NotSupportedException ();
7314 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7315 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7319 public override object Accept (StructuralVisitor visitor)
7321 return visitor.Visit (this);
7326 // Implements simple new expression
7328 public class New : ExpressionStatement, IMemoryLocation
7330 protected Arguments arguments;
7333 // During bootstrap, it contains the RequestedType,
7334 // but if `type' is not null, it *might* contain a NewDelegate
7335 // (because of field multi-initialization)
7337 protected Expression RequestedType;
7339 protected MethodSpec method;
7341 public New (Expression requested_type, Arguments arguments, Location l)
7343 RequestedType = requested_type;
7344 this.arguments = arguments;
7349 public Arguments Arguments {
7356 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7358 public bool IsGeneratedStructConstructor {
7360 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7364 public Expression TypeExpression {
7366 return RequestedType;
7373 /// Converts complex core type syntax like 'new int ()' to simple constant
7375 public static Constant Constantify (TypeSpec t, Location loc)
7377 switch (t.BuiltinType) {
7378 case BuiltinTypeSpec.Type.Int:
7379 return new IntConstant (t, 0, loc);
7380 case BuiltinTypeSpec.Type.UInt:
7381 return new UIntConstant (t, 0, loc);
7382 case BuiltinTypeSpec.Type.Long:
7383 return new LongConstant (t, 0, loc);
7384 case BuiltinTypeSpec.Type.ULong:
7385 return new ULongConstant (t, 0, loc);
7386 case BuiltinTypeSpec.Type.Float:
7387 return new FloatConstant (t, 0, loc);
7388 case BuiltinTypeSpec.Type.Double:
7389 return new DoubleConstant (t, 0, loc);
7390 case BuiltinTypeSpec.Type.Short:
7391 return new ShortConstant (t, 0, loc);
7392 case BuiltinTypeSpec.Type.UShort:
7393 return new UShortConstant (t, 0, loc);
7394 case BuiltinTypeSpec.Type.SByte:
7395 return new SByteConstant (t, 0, loc);
7396 case BuiltinTypeSpec.Type.Byte:
7397 return new ByteConstant (t, 0, loc);
7398 case BuiltinTypeSpec.Type.Char:
7399 return new CharConstant (t, '\0', loc);
7400 case BuiltinTypeSpec.Type.Bool:
7401 return new BoolConstant (t, false, loc);
7402 case BuiltinTypeSpec.Type.Decimal:
7403 return new DecimalConstant (t, 0, loc);
7407 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7409 if (t.IsNullableType)
7410 return Nullable.LiftedNull.Create (t, loc);
7415 public override bool ContainsEmitWithAwait ()
7417 return arguments != null && arguments.ContainsEmitWithAwait ();
7421 // Checks whether the type is an interface that has the
7422 // [ComImport, CoClass] attributes and must be treated
7425 public Expression CheckComImport (ResolveContext ec)
7427 if (!type.IsInterface)
7431 // Turn the call into:
7432 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7434 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7435 if (real_class == null)
7438 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7439 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7440 return cast.Resolve (ec);
7443 public override Expression CreateExpressionTree (ResolveContext ec)
7446 if (method == null) {
7447 args = new Arguments (1);
7448 args.Add (new Argument (new TypeOf (type, loc)));
7450 args = Arguments.CreateForExpressionTree (ec,
7451 arguments, new TypeOfMethod (method, loc));
7454 return CreateExpressionFactoryCall (ec, "New", args);
7457 protected override Expression DoResolve (ResolveContext ec)
7459 type = RequestedType.ResolveAsType (ec);
7463 eclass = ExprClass.Value;
7465 if (type.IsPointer) {
7466 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7467 type.GetSignatureForError ());
7471 if (arguments == null) {
7472 Constant c = Constantify (type, RequestedType.Location);
7474 return ReducedExpression.Create (c, this);
7477 if (type.IsDelegate) {
7478 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7481 var tparam = type as TypeParameterSpec;
7482 if (tparam != null) {
7484 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7485 // where type parameter constraint is inflated to struct
7487 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7488 ec.Report.Error (304, loc,
7489 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7490 type.GetSignatureForError ());
7493 if ((arguments != null) && (arguments.Count != 0)) {
7494 ec.Report.Error (417, loc,
7495 "`{0}': cannot provide arguments when creating an instance of a variable type",
7496 type.GetSignatureForError ());
7502 if (type.IsStatic) {
7503 ec.Report.SymbolRelatedToPreviousError (type);
7504 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7508 if (type.IsInterface || type.IsAbstract){
7509 if (!TypeManager.IsGenericType (type)) {
7510 RequestedType = CheckComImport (ec);
7511 if (RequestedType != null)
7512 return RequestedType;
7515 ec.Report.SymbolRelatedToPreviousError (type);
7516 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7521 if (arguments != null) {
7522 arguments.Resolve (ec, out dynamic);
7527 method = ConstructorLookup (ec, type, ref arguments, loc);
7530 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7531 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7537 void DoEmitTypeParameter (EmitContext ec)
7539 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7543 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7544 ec.Emit (OpCodes.Call, ctor_factory);
7548 // This Emit can be invoked in two contexts:
7549 // * As a mechanism that will leave a value on the stack (new object)
7550 // * As one that wont (init struct)
7552 // If we are dealing with a ValueType, we have a few
7553 // situations to deal with:
7555 // * The target is a ValueType, and we have been provided
7556 // the instance (this is easy, we are being assigned).
7558 // * The target of New is being passed as an argument,
7559 // to a boxing operation or a function that takes a
7562 // In this case, we need to create a temporary variable
7563 // that is the argument of New.
7565 // Returns whether a value is left on the stack
7567 // *** Implementation note ***
7569 // To benefit from this optimization, each assignable expression
7570 // has to manually cast to New and call this Emit.
7572 // TODO: It's worth to implement it for arrays and fields
7574 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7576 bool is_value_type = type.IsStructOrEnum;
7577 VariableReference vr = target as VariableReference;
7579 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7581 if (target != null && is_value_type && (vr != null || method == null)) {
7582 if (prepare_await) {
7583 arguments = arguments.Emit (ec, false, true);
7584 prepare_await = false;
7587 target.AddressOf (ec, AddressOp.Store);
7588 } else if (vr != null && vr.IsRef) {
7592 if (arguments != null) {
7594 arguments = arguments.Emit (ec, false, true);
7596 arguments.Emit (ec);
7599 if (is_value_type) {
7600 if (method == null) {
7601 ec.Emit (OpCodes.Initobj, type);
7606 ec.MarkCallEntry (loc);
7607 ec.Emit (OpCodes.Call, method);
7612 if (type is TypeParameterSpec) {
7613 DoEmitTypeParameter (ec);
7617 ec.MarkCallEntry (loc);
7618 ec.Emit (OpCodes.Newobj, method);
7622 public override void Emit (EmitContext ec)
7624 LocalTemporary v = null;
7625 if (method == null && type.IsStructOrEnum) {
7626 // TODO: Use temporary variable from pool
7627 v = new LocalTemporary (type);
7634 public override void EmitStatement (EmitContext ec)
7636 LocalTemporary v = null;
7637 if (method == null && TypeSpec.IsValueType (type)) {
7638 // TODO: Use temporary variable from pool
7639 v = new LocalTemporary (type);
7643 ec.Emit (OpCodes.Pop);
7646 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7651 public override void FlowAnalysis (FlowAnalysisContext fc)
7653 if (arguments != null)
7654 arguments.FlowAnalysis (fc);
7657 public void AddressOf (EmitContext ec, AddressOp mode)
7659 EmitAddressOf (ec, mode);
7662 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7664 LocalTemporary value_target = new LocalTemporary (type);
7666 if (type is TypeParameterSpec) {
7667 DoEmitTypeParameter (ec);
7668 value_target.Store (ec);
7669 value_target.AddressOf (ec, mode);
7670 return value_target;
7673 value_target.AddressOf (ec, AddressOp.Store);
7675 if (method == null) {
7676 ec.Emit (OpCodes.Initobj, type);
7678 if (arguments != null)
7679 arguments.Emit (ec);
7681 ec.Emit (OpCodes.Call, method);
7684 value_target.AddressOf (ec, mode);
7685 return value_target;
7688 protected override void CloneTo (CloneContext clonectx, Expression t)
7690 New target = (New) t;
7692 target.RequestedType = RequestedType.Clone (clonectx);
7693 if (arguments != null){
7694 target.arguments = arguments.Clone (clonectx);
7698 public override SLE.Expression MakeExpression (BuilderContext ctx)
7701 return base.MakeExpression (ctx);
7703 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7707 public override object Accept (StructuralVisitor visitor)
7709 return visitor.Visit (this);
7714 // Array initializer expression, the expression is allowed in
7715 // variable or field initialization only which makes it tricky as
7716 // the type has to be infered based on the context either from field
7717 // type or variable type (think of multiple declarators)
7719 public class ArrayInitializer : Expression
7721 List<Expression> elements;
7722 BlockVariable variable;
7724 public ArrayInitializer (List<Expression> init, Location loc)
7730 public ArrayInitializer (int count, Location loc)
7731 : this (new List<Expression> (count), loc)
7735 public ArrayInitializer (Location loc)
7743 get { return elements.Count; }
7746 public List<Expression> Elements {
7752 public Expression this [int index] {
7754 return elements [index];
7758 public BlockVariable VariableDeclaration {
7769 public void Add (Expression expr)
7771 elements.Add (expr);
7774 public override bool ContainsEmitWithAwait ()
7776 throw new NotSupportedException ();
7779 public override Expression CreateExpressionTree (ResolveContext ec)
7781 throw new NotSupportedException ("ET");
7784 protected override void CloneTo (CloneContext clonectx, Expression t)
7786 var target = (ArrayInitializer) t;
7788 target.elements = new List<Expression> (elements.Count);
7789 foreach (var element in elements)
7790 target.elements.Add (element.Clone (clonectx));
7793 protected override Expression DoResolve (ResolveContext rc)
7795 var current_field = rc.CurrentMemberDefinition as FieldBase;
7796 TypeExpression type;
7797 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7798 type = new TypeExpression (current_field.MemberType, current_field.Location);
7799 } else if (variable != null) {
7800 if (variable.TypeExpression is VarExpr) {
7801 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7802 return EmptyExpression.Null;
7805 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7807 throw new NotImplementedException ("Unexpected array initializer context");
7810 return new ArrayCreation (type, this).Resolve (rc);
7813 public override void Emit (EmitContext ec)
7815 throw new InternalErrorException ("Missing Resolve call");
7818 public override void FlowAnalysis (FlowAnalysisContext fc)
7820 throw new InternalErrorException ("Missing Resolve call");
7823 public override object Accept (StructuralVisitor visitor)
7825 return visitor.Visit (this);
7830 /// 14.5.10.2: Represents an array creation expression.
7834 /// There are two possible scenarios here: one is an array creation
7835 /// expression that specifies the dimensions and optionally the
7836 /// initialization data and the other which does not need dimensions
7837 /// specified but where initialization data is mandatory.
7839 public class ArrayCreation : Expression
7841 FullNamedExpression requested_base_type;
7842 ArrayInitializer initializers;
7845 // The list of Argument types.
7846 // This is used to construct the `newarray' or constructor signature
7848 protected List<Expression> arguments;
7850 protected TypeSpec array_element_type;
7852 protected int dimensions;
7853 protected readonly ComposedTypeSpecifier rank;
7854 Expression first_emit;
7855 LocalTemporary first_emit_temp;
7857 protected List<Expression> array_data;
7859 Dictionary<int, int> bounds;
7862 // The number of constants in array initializers
7863 int const_initializers_count;
7864 bool only_constant_initializers;
7866 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7867 : this (requested_base_type, rank, initializers, l)
7869 arguments = new List<Expression> (exprs);
7870 num_arguments = arguments.Count;
7874 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7876 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7878 this.requested_base_type = requested_base_type;
7880 this.initializers = initializers;
7884 num_arguments = rank.Dimension;
7888 // For compiler generated single dimensional arrays only
7890 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7891 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7896 // For expressions like int[] foo = { 1, 2, 3 };
7898 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7899 : this (requested_base_type, null, initializers, initializers.Location)
7903 public bool NoEmptyInterpolation { get; set; }
7905 public ComposedTypeSpecifier Rank {
7911 public FullNamedExpression TypeExpression {
7913 return this.requested_base_type;
7917 public ArrayInitializer Initializers {
7919 return this.initializers;
7923 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7925 if (initializers != null && bounds == null) {
7927 // We use this to store all the data values in the order in which we
7928 // will need to store them in the byte blob later
7930 array_data = new List<Expression> (probe.Count);
7931 bounds = new Dictionary<int, int> ();
7934 if (specified_dims) {
7935 Expression a = arguments [idx];
7940 a = ConvertExpressionToArrayIndex (ec, a);
7946 if (initializers != null) {
7947 Constant c = a as Constant;
7948 if (c == null && a is ArrayIndexCast)
7949 c = ((ArrayIndexCast) a).Child as Constant;
7952 ec.Report.Error (150, a.Location, "A constant value is expected");
7958 value = System.Convert.ToInt32 (c.GetValue ());
7960 ec.Report.Error (150, a.Location, "A constant value is expected");
7964 // TODO: probe.Count does not fit ulong in
7965 if (value != probe.Count) {
7966 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7970 bounds[idx] = value;
7974 if (initializers == null)
7977 for (int i = 0; i < probe.Count; ++i) {
7979 if (o is ArrayInitializer) {
7980 var sub_probe = o as ArrayInitializer;
7981 if (idx + 1 >= dimensions){
7982 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7986 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7987 if (!bounds.ContainsKey(idx + 1))
7988 bounds[idx + 1] = sub_probe.Count;
7990 if (bounds[idx + 1] != sub_probe.Count) {
7991 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7995 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7998 } else if (child_bounds > 1) {
7999 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8001 Expression element = ResolveArrayElement (ec, o);
8002 if (element == null)
8005 // Initializers with the default values can be ignored
8006 Constant c = element as Constant;
8008 if (!c.IsDefaultInitializer (array_element_type)) {
8009 ++const_initializers_count;
8012 only_constant_initializers = false;
8015 array_data.Add (element);
8022 public override bool ContainsEmitWithAwait ()
8024 foreach (var arg in arguments) {
8025 if (arg.ContainsEmitWithAwait ())
8029 return InitializersContainAwait ();
8032 public override Expression CreateExpressionTree (ResolveContext ec)
8036 if (array_data == null) {
8037 args = new Arguments (arguments.Count + 1);
8038 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8039 foreach (Expression a in arguments)
8040 args.Add (new Argument (a.CreateExpressionTree (ec)));
8042 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8045 if (dimensions > 1) {
8046 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8050 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8051 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8052 if (array_data != null) {
8053 for (int i = 0; i < array_data.Count; ++i) {
8054 Expression e = array_data [i];
8055 args.Add (new Argument (e.CreateExpressionTree (ec)));
8059 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8062 void UpdateIndices (ResolveContext rc)
8065 for (var probe = initializers; probe != null;) {
8066 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8068 bounds[i++] = probe.Count;
8070 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8071 probe = (ArrayInitializer) probe[0];
8072 } else if (dimensions > i) {
8080 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8082 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8085 public override void FlowAnalysis (FlowAnalysisContext fc)
8087 foreach (var arg in arguments)
8088 arg.FlowAnalysis (fc);
8090 if (array_data != null) {
8091 foreach (var ad in array_data)
8092 ad.FlowAnalysis (fc);
8096 bool InitializersContainAwait ()
8098 if (array_data == null)
8101 foreach (var expr in array_data) {
8102 if (expr.ContainsEmitWithAwait ())
8109 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8111 element = element.Resolve (ec);
8112 if (element == null)
8115 var te = element as CompoundAssign.TargetExpression;
8117 for (int i = 1; i < initializers.Count; ++i) {
8118 if (initializers [i].ContainsEmitWithAwait ()) {
8119 te.RequiresEmitWithAwait = true;
8124 if (!te.RequiresEmitWithAwait) {
8125 if (first_emit != null)
8126 throw new InternalErrorException ("Can only handle one mutator at a time");
8127 first_emit = element;
8128 element = first_emit_temp = new LocalTemporary (element.Type);
8132 return Convert.ImplicitConversionRequired (
8133 ec, element, array_element_type, loc);
8136 protected bool ResolveInitializers (ResolveContext ec)
8139 only_constant_initializers = true;
8142 if (arguments != null) {
8144 for (int i = 0; i < arguments.Count; ++i) {
8145 res &= CheckIndices (ec, initializers, i, true, dimensions);
8146 if (initializers != null)
8153 arguments = new List<Expression> ();
8155 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8164 // Resolved the type of the array
8166 bool ResolveArrayType (ResolveContext ec)
8171 FullNamedExpression array_type_expr;
8172 if (num_arguments > 0) {
8173 array_type_expr = new ComposedCast (requested_base_type, rank);
8175 array_type_expr = requested_base_type;
8178 type = array_type_expr.ResolveAsType (ec);
8179 if (array_type_expr == null)
8182 var ac = type as ArrayContainer;
8184 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8188 array_element_type = ac.Element;
8189 dimensions = ac.Rank;
8194 protected override Expression DoResolve (ResolveContext ec)
8199 if (!ResolveArrayType (ec))
8203 // validate the initializers and fill in any missing bits
8205 if (!ResolveInitializers (ec))
8208 eclass = ExprClass.Value;
8212 byte [] MakeByteBlob ()
8217 int count = array_data.Count;
8219 TypeSpec element_type = array_element_type;
8220 if (element_type.IsEnum)
8221 element_type = EnumSpec.GetUnderlyingType (element_type);
8223 factor = BuiltinTypeSpec.GetSize (element_type);
8225 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8227 data = new byte [(count * factor + 3) & ~3];
8230 for (int i = 0; i < count; ++i) {
8231 var c = array_data[i] as Constant;
8237 object v = c.GetValue ();
8239 switch (element_type.BuiltinType) {
8240 case BuiltinTypeSpec.Type.Long:
8241 long lval = (long) v;
8243 for (int j = 0; j < factor; ++j) {
8244 data[idx + j] = (byte) (lval & 0xFF);
8248 case BuiltinTypeSpec.Type.ULong:
8249 ulong ulval = (ulong) v;
8251 for (int j = 0; j < factor; ++j) {
8252 data[idx + j] = (byte) (ulval & 0xFF);
8253 ulval = (ulval >> 8);
8256 case BuiltinTypeSpec.Type.Float:
8257 var fval = SingleConverter.SingleToInt32Bits((float) v);
8259 data[idx] = (byte) (fval & 0xff);
8260 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8261 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8262 data[idx + 3] = (byte) (fval >> 24);
8264 case BuiltinTypeSpec.Type.Double:
8265 element = BitConverter.GetBytes ((double) v);
8267 for (int j = 0; j < factor; ++j)
8268 data[idx + j] = element[j];
8270 // FIXME: Handle the ARM float format.
8271 if (!BitConverter.IsLittleEndian)
8272 System.Array.Reverse (data, idx, 8);
8274 case BuiltinTypeSpec.Type.Char:
8275 int chval = (int) ((char) v);
8277 data[idx] = (byte) (chval & 0xff);
8278 data[idx + 1] = (byte) (chval >> 8);
8280 case BuiltinTypeSpec.Type.Short:
8281 int sval = (int) ((short) v);
8283 data[idx] = (byte) (sval & 0xff);
8284 data[idx + 1] = (byte) (sval >> 8);
8286 case BuiltinTypeSpec.Type.UShort:
8287 int usval = (int) ((ushort) v);
8289 data[idx] = (byte) (usval & 0xff);
8290 data[idx + 1] = (byte) (usval >> 8);
8292 case BuiltinTypeSpec.Type.Int:
8295 data[idx] = (byte) (val & 0xff);
8296 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8297 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8298 data[idx + 3] = (byte) (val >> 24);
8300 case BuiltinTypeSpec.Type.UInt:
8301 uint uval = (uint) v;
8303 data[idx] = (byte) (uval & 0xff);
8304 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8305 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8306 data[idx + 3] = (byte) (uval >> 24);
8308 case BuiltinTypeSpec.Type.SByte:
8309 data[idx] = (byte) (sbyte) v;
8311 case BuiltinTypeSpec.Type.Byte:
8312 data[idx] = (byte) v;
8314 case BuiltinTypeSpec.Type.Bool:
8315 data[idx] = (byte) ((bool) v ? 1 : 0);
8317 case BuiltinTypeSpec.Type.Decimal:
8318 int[] bits = Decimal.GetBits ((decimal) v);
8321 // FIXME: For some reason, this doesn't work on the MS runtime.
8322 int[] nbits = new int[4];
8328 for (int j = 0; j < 4; j++) {
8329 data[p++] = (byte) (nbits[j] & 0xff);
8330 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8331 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8332 data[p++] = (byte) (nbits[j] >> 24);
8336 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8345 public override SLE.Expression MakeExpression (BuilderContext ctx)
8348 return base.MakeExpression (ctx);
8350 var initializers = new SLE.Expression [array_data.Count];
8351 for (var i = 0; i < initializers.Length; i++) {
8352 if (array_data [i] == null)
8353 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8355 initializers [i] = array_data [i].MakeExpression (ctx);
8358 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8363 // Emits the initializers for the array
8365 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8367 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8372 // First, the static data
8374 byte [] data = MakeByteBlob ();
8375 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8377 if (stackArray == null) {
8378 ec.Emit (OpCodes.Dup);
8380 stackArray.Emit (ec);
8383 ec.Emit (OpCodes.Ldtoken, fb);
8384 ec.Emit (OpCodes.Call, m);
8389 // Emits pieces of the array that can not be computed at compile
8390 // time (variables and string locations).
8392 // This always expect the top value on the stack to be the array
8394 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8396 int dims = bounds.Count;
8397 var current_pos = new int [dims];
8399 for (int i = 0; i < array_data.Count; i++){
8401 Expression e = array_data [i];
8402 var c = e as Constant;
8404 // Constant can be initialized via StaticInitializer
8405 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8409 if (stackArray != null) {
8410 if (e.ContainsEmitWithAwait ()) {
8411 e = e.EmitToField (ec);
8414 stackArray.EmitLoad (ec);
8416 ec.Emit (OpCodes.Dup);
8419 for (int idx = 0; idx < dims; idx++)
8420 ec.EmitInt (current_pos [idx]);
8423 // If we are dealing with a struct, get the
8424 // address of it, so we can store it.
8426 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8427 ec.Emit (OpCodes.Ldelema, etype);
8431 ec.EmitArrayStore ((ArrayContainer) type);
8437 for (int j = dims - 1; j >= 0; j--){
8439 if (current_pos [j] < bounds [j])
8441 current_pos [j] = 0;
8445 if (stackArray != null)
8446 stackArray.PrepareCleanup (ec);
8449 public override void Emit (EmitContext ec)
8451 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8454 var await_field = EmitToFieldSource (ec);
8455 if (await_field != null)
8456 await_field.Emit (ec);
8459 bool EmitOptimizedEmpty (EmitContext ec)
8461 if (arguments.Count != 1 || dimensions != 1)
8464 var c = arguments [0] as Constant;
8465 if (c == null || !c.IsZeroInteger)
8468 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8469 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8472 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8473 ec.Emit (OpCodes.Call, m);
8477 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8479 if (first_emit != null) {
8480 first_emit.Emit (ec);
8481 first_emit_temp.Store (ec);
8484 StackFieldExpr await_stack_field;
8485 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8486 await_stack_field = ec.GetTemporaryField (type);
8489 await_stack_field = null;
8492 EmitExpressionsList (ec, arguments);
8494 ec.EmitArrayNew ((ArrayContainer) type);
8496 if (initializers == null)
8497 return await_stack_field;
8499 if (await_stack_field != null)
8500 await_stack_field.EmitAssignFromStack (ec);
8504 // Emit static initializer for arrays which contain more than 2 items and
8505 // the static initializer will initialize at least 25% of array values or there
8506 // is more than 10 items to be initialized
8508 // NOTE: const_initializers_count does not contain default constant values.
8510 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8511 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8512 EmitStaticInitializers (ec, await_stack_field);
8514 if (!only_constant_initializers)
8515 EmitDynamicInitializers (ec, false, await_stack_field);
8519 EmitDynamicInitializers (ec, true, await_stack_field);
8522 if (first_emit_temp != null)
8523 first_emit_temp.Release (ec);
8525 return await_stack_field;
8528 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8530 // no multi dimensional or jagged arrays
8531 if (arguments.Count != 1 || array_element_type.IsArray) {
8532 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8536 // No array covariance, except for array -> object
8537 if (type != targetType) {
8538 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8539 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8543 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8544 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8549 // Single dimensional array of 0 size
8550 if (array_data == null) {
8551 IntConstant ic = arguments[0] as IntConstant;
8552 if (ic == null || !ic.IsDefaultValue) {
8553 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8561 enc.Encode (array_data.Count);
8562 foreach (var element in array_data) {
8563 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8567 protected override void CloneTo (CloneContext clonectx, Expression t)
8569 ArrayCreation target = (ArrayCreation) t;
8571 if (requested_base_type != null)
8572 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8574 if (arguments != null){
8575 target.arguments = new List<Expression> (arguments.Count);
8576 foreach (Expression e in arguments)
8577 target.arguments.Add (e.Clone (clonectx));
8580 if (initializers != null)
8581 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8584 public override object Accept (StructuralVisitor visitor)
8586 return visitor.Visit (this);
8591 // Represents an implicitly typed array epxression
8593 class ImplicitlyTypedArrayCreation : ArrayCreation
8595 TypeInferenceContext best_type_inference;
8597 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8598 : base (null, rank, initializers, loc)
8602 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8603 : base (null, initializers, loc)
8607 protected override Expression DoResolve (ResolveContext ec)
8612 dimensions = rank.Dimension;
8614 best_type_inference = new TypeInferenceContext ();
8616 if (!ResolveInitializers (ec))
8619 best_type_inference.FixAllTypes (ec);
8620 array_element_type = best_type_inference.InferredTypeArguments[0];
8621 best_type_inference = null;
8623 if (array_element_type == null ||
8624 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8625 arguments.Count != rank.Dimension) {
8626 ec.Report.Error (826, loc,
8627 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8632 // At this point we found common base type for all initializer elements
8633 // but we have to be sure that all static initializer elements are of
8636 UnifyInitializerElement (ec);
8638 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8639 eclass = ExprClass.Value;
8644 // Converts static initializer only
8646 void UnifyInitializerElement (ResolveContext ec)
8648 for (int i = 0; i < array_data.Count; ++i) {
8649 Expression e = array_data[i];
8651 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8655 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8657 element = element.Resolve (ec);
8658 if (element != null)
8659 best_type_inference.AddCommonTypeBound (element.Type);
8665 sealed class CompilerGeneratedThis : This
8667 public CompilerGeneratedThis (TypeSpec type, Location loc)
8673 protected override Expression DoResolve (ResolveContext rc)
8675 eclass = ExprClass.Variable;
8677 var block = rc.CurrentBlock;
8678 if (block != null) {
8679 var top = block.ParametersBlock.TopBlock;
8680 if (top.ThisVariable != null)
8681 variable_info = top.ThisVariable.VariableInfo;
8688 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8690 return DoResolve (rc);
8693 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8700 /// Represents the `this' construct
8703 public class This : VariableReference
8705 sealed class ThisVariable : ILocalVariable
8707 public static readonly ILocalVariable Instance = new ThisVariable ();
8709 public void Emit (EmitContext ec)
8714 public void EmitAssign (EmitContext ec)
8716 throw new InvalidOperationException ();
8719 public void EmitAddressOf (EmitContext ec)
8725 protected VariableInfo variable_info;
8727 public This (Location loc)
8734 public override string Name {
8735 get { return "this"; }
8738 public override bool IsLockedByStatement {
8746 public override bool IsRef {
8747 get { return type.IsStruct; }
8750 public override bool IsSideEffectFree {
8756 protected override ILocalVariable Variable {
8757 get { return ThisVariable.Instance; }
8760 public override VariableInfo VariableInfo {
8761 get { return variable_info; }
8764 public override bool IsFixed {
8765 get { return false; }
8770 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8773 // It's null for all cases when we don't need to check `this'
8774 // definitive assignment
8776 if (variable_info == null)
8779 if (fc.IsDefinitelyAssigned (variable_info))
8782 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8785 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8787 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8788 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8789 } else if (ec.CurrentAnonymousMethod != null) {
8790 ec.Report.Error (1673, loc,
8791 "Anonymous methods inside structs cannot access instance members of `this'. " +
8792 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8794 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8798 public override void FlowAnalysis (FlowAnalysisContext fc)
8800 CheckStructThisDefiniteAssignment (fc);
8803 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8808 AnonymousMethodStorey storey = ae.Storey;
8809 return storey != null ? storey.HoistedThis : null;
8812 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8814 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8817 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8820 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8826 public virtual void ResolveBase (ResolveContext ec)
8828 eclass = ExprClass.Variable;
8829 type = ec.CurrentType;
8831 if (!IsThisAvailable (ec, false)) {
8832 Error_ThisNotAvailable (ec);
8836 var block = ec.CurrentBlock;
8837 if (block != null) {
8838 var top = block.ParametersBlock.TopBlock;
8839 if (top.ThisVariable != null)
8840 variable_info = top.ThisVariable.VariableInfo;
8842 AnonymousExpression am = ec.CurrentAnonymousMethod;
8843 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8845 // Hoisted this is almost like hoisted variable but not exactly. When
8846 // there is no variable hoisted we can simply emit an instance method
8847 // without lifting this into a storey. Unfotunatelly this complicates
8848 // things in other cases because we don't know where this will be hoisted
8849 // until top-level block is fully resolved
8851 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8852 am.SetHasThisAccess ();
8857 protected override Expression DoResolve (ResolveContext ec)
8863 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8865 if (eclass == ExprClass.Unresolved)
8869 if (right_side == EmptyExpression.UnaryAddress)
8870 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8871 else if (right_side == EmptyExpression.OutAccess)
8872 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8874 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8880 public override int GetHashCode()
8882 throw new NotImplementedException ();
8885 public override bool Equals (object obj)
8887 This t = obj as This;
8894 protected override void CloneTo (CloneContext clonectx, Expression t)
8899 public override void SetHasAddressTaken ()
8904 public override object Accept (StructuralVisitor visitor)
8906 return visitor.Visit (this);
8911 /// Represents the `__arglist' construct
8913 public class ArglistAccess : Expression
8915 public ArglistAccess (Location loc)
8920 protected override void CloneTo (CloneContext clonectx, Expression target)
8925 public override bool ContainsEmitWithAwait ()
8930 public override Expression CreateExpressionTree (ResolveContext ec)
8932 throw new NotSupportedException ("ET");
8935 protected override Expression DoResolve (ResolveContext ec)
8937 eclass = ExprClass.Variable;
8938 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8940 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8941 ec.Report.Error (190, loc,
8942 "The __arglist construct is valid only within a variable argument method");
8948 public override void Emit (EmitContext ec)
8950 ec.Emit (OpCodes.Arglist);
8953 public override object Accept (StructuralVisitor visitor)
8955 return visitor.Visit (this);
8960 /// Represents the `__arglist (....)' construct
8962 public class Arglist : Expression
8964 Arguments arguments;
8966 public Arglist (Location loc)
8971 public Arglist (Arguments args, Location l)
8977 public Arguments Arguments {
8983 public MetaType[] ArgumentTypes {
8985 if (arguments == null)
8986 return MetaType.EmptyTypes;
8988 var retval = new MetaType[arguments.Count];
8989 for (int i = 0; i < retval.Length; i++)
8990 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8996 public override bool ContainsEmitWithAwait ()
8998 throw new NotImplementedException ();
9001 public override Expression CreateExpressionTree (ResolveContext ec)
9003 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9007 protected override Expression DoResolve (ResolveContext ec)
9009 eclass = ExprClass.Variable;
9010 type = InternalType.Arglist;
9011 if (arguments != null) {
9012 bool dynamic; // Can be ignored as there is always only 1 overload
9013 arguments.Resolve (ec, out dynamic);
9019 public override void Emit (EmitContext ec)
9021 if (arguments != null)
9022 arguments.Emit (ec);
9025 protected override void CloneTo (CloneContext clonectx, Expression t)
9027 Arglist target = (Arglist) t;
9029 if (arguments != null)
9030 target.arguments = arguments.Clone (clonectx);
9033 public override object Accept (StructuralVisitor visitor)
9035 return visitor.Visit (this);
9039 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9041 FullNamedExpression texpr;
9043 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9050 public FullNamedExpression TypeExpression {
9056 public override bool ContainsEmitWithAwait ()
9061 public void AddressOf (EmitContext ec, AddressOp mode)
9064 ec.Emit (OpCodes.Refanyval, type);
9067 protected override Expression DoResolve (ResolveContext rc)
9069 expr = expr.Resolve (rc);
9070 type = texpr.ResolveAsType (rc);
9071 if (expr == null || type == null)
9074 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9075 eclass = ExprClass.Variable;
9079 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9081 return DoResolve (rc);
9084 public override void Emit (EmitContext ec)
9087 ec.Emit (OpCodes.Refanyval, type);
9088 ec.EmitLoadFromPtr (type);
9091 public void Emit (EmitContext ec, bool leave_copy)
9093 throw new NotImplementedException ();
9096 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9099 ec.Emit (OpCodes.Refanyval, type);
9102 LocalTemporary temporary = null;
9104 ec.Emit (OpCodes.Dup);
9105 temporary = new LocalTemporary (source.Type);
9106 temporary.Store (ec);
9109 ec.EmitStoreFromPtr (type);
9111 if (temporary != null) {
9112 temporary.Emit (ec);
9113 temporary.Release (ec);
9117 public override object Accept (StructuralVisitor visitor)
9119 return visitor.Visit (this);
9123 public class RefTypeExpr : ShimExpression
9125 public RefTypeExpr (Expression expr, Location loc)
9131 protected override Expression DoResolve (ResolveContext rc)
9133 expr = expr.Resolve (rc);
9137 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9141 type = rc.BuiltinTypes.Type;
9142 eclass = ExprClass.Value;
9146 public override void Emit (EmitContext ec)
9149 ec.Emit (OpCodes.Refanytype);
9150 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9152 ec.Emit (OpCodes.Call, m);
9155 public override object Accept (StructuralVisitor visitor)
9157 return visitor.Visit (this);
9161 public class MakeRefExpr : ShimExpression
9163 public MakeRefExpr (Expression expr, Location loc)
9169 public override bool ContainsEmitWithAwait ()
9171 throw new NotImplementedException ();
9174 protected override Expression DoResolve (ResolveContext rc)
9176 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9177 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9178 eclass = ExprClass.Value;
9182 public override void Emit (EmitContext ec)
9184 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9185 ec.Emit (OpCodes.Mkrefany, expr.Type);
9188 public override object Accept (StructuralVisitor visitor)
9190 return visitor.Visit (this);
9195 /// Implements the typeof operator
9197 public class TypeOf : Expression {
9198 FullNamedExpression QueriedType;
9201 public TypeOf (FullNamedExpression queried_type, Location l)
9203 QueriedType = queried_type;
9208 // Use this constructor for any compiler generated typeof expression
9210 public TypeOf (TypeSpec type, Location loc)
9212 this.typearg = type;
9218 public override bool IsSideEffectFree {
9224 public TypeSpec TypeArgument {
9230 public FullNamedExpression TypeExpression {
9239 protected override void CloneTo (CloneContext clonectx, Expression t)
9241 TypeOf target = (TypeOf) t;
9242 if (QueriedType != null)
9243 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9246 public override bool ContainsEmitWithAwait ()
9251 public override Expression CreateExpressionTree (ResolveContext ec)
9253 Arguments args = new Arguments (2);
9254 args.Add (new Argument (this));
9255 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9256 return CreateExpressionFactoryCall (ec, "Constant", args);
9259 protected override Expression DoResolve (ResolveContext ec)
9261 if (eclass != ExprClass.Unresolved)
9264 if (typearg == null) {
9266 // Pointer types are allowed without explicit unsafe, they are just tokens
9268 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9269 typearg = QueriedType.ResolveAsType (ec, true);
9272 if (typearg == null)
9275 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9276 ec.Report.Error (1962, QueriedType.Location,
9277 "The typeof operator cannot be used on the dynamic type");
9281 type = ec.BuiltinTypes.Type;
9283 // Even though what is returned is a type object, it's treated as a value by the compiler.
9284 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9285 eclass = ExprClass.Value;
9289 static bool ContainsDynamicType (TypeSpec type)
9291 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9294 var element_container = type as ElementTypeSpec;
9295 if (element_container != null)
9296 return ContainsDynamicType (element_container.Element);
9298 foreach (var t in type.TypeArguments) {
9299 if (ContainsDynamicType (t)) {
9307 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9309 // Target type is not System.Type therefore must be object
9310 // and we need to use different encoding sequence
9311 if (targetType != type)
9314 if (typearg is InflatedTypeSpec) {
9317 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9318 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9319 typearg.GetSignatureForError ());
9323 gt = gt.DeclaringType;
9324 } while (gt != null);
9327 if (ContainsDynamicType (typearg)) {
9328 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9332 enc.EncodeTypeName (typearg);
9335 public override void Emit (EmitContext ec)
9337 ec.Emit (OpCodes.Ldtoken, typearg);
9338 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9340 ec.Emit (OpCodes.Call, m);
9343 public override object Accept (StructuralVisitor visitor)
9345 return visitor.Visit (this);
9349 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9351 public TypeOfMethod (MethodSpec method, Location loc)
9352 : base (method, loc)
9356 protected override Expression DoResolve (ResolveContext ec)
9358 if (member.IsConstructor) {
9359 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9361 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9367 return base.DoResolve (ec);
9370 public override void Emit (EmitContext ec)
9372 ec.Emit (OpCodes.Ldtoken, member);
9375 ec.Emit (OpCodes.Castclass, type);
9378 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9380 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9383 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9385 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9389 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9391 protected readonly T member;
9393 protected TypeOfMember (T member, Location loc)
9395 this.member = member;
9399 public override bool IsSideEffectFree {
9405 public override bool ContainsEmitWithAwait ()
9410 public override Expression CreateExpressionTree (ResolveContext ec)
9412 Arguments args = new Arguments (2);
9413 args.Add (new Argument (this));
9414 args.Add (new Argument (new TypeOf (type, loc)));
9415 return CreateExpressionFactoryCall (ec, "Constant", args);
9418 protected override Expression DoResolve (ResolveContext ec)
9420 eclass = ExprClass.Value;
9424 public override void Emit (EmitContext ec)
9426 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9427 PredefinedMember<MethodSpec> p;
9429 p = GetTypeFromHandleGeneric (ec);
9430 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9432 p = GetTypeFromHandle (ec);
9435 var mi = p.Resolve (loc);
9437 ec.Emit (OpCodes.Call, mi);
9440 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9441 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9444 sealed class TypeOfField : TypeOfMember<FieldSpec>
9446 public TypeOfField (FieldSpec field, Location loc)
9451 protected override Expression DoResolve (ResolveContext ec)
9453 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9457 return base.DoResolve (ec);
9460 public override void Emit (EmitContext ec)
9462 ec.Emit (OpCodes.Ldtoken, member);
9466 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9468 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9471 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9473 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9478 /// Implements the sizeof expression
9480 public class SizeOf : Expression {
9481 readonly Expression texpr;
9482 TypeSpec type_queried;
9484 public SizeOf (Expression queried_type, Location l)
9486 this.texpr = queried_type;
9490 public override bool IsSideEffectFree {
9496 public Expression TypeExpression {
9502 public override bool ContainsEmitWithAwait ()
9507 public override Expression CreateExpressionTree (ResolveContext ec)
9509 Error_PointerInsideExpressionTree (ec);
9513 protected override Expression DoResolve (ResolveContext ec)
9515 type_queried = texpr.ResolveAsType (ec);
9516 if (type_queried == null)
9519 if (type_queried.IsEnum)
9520 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9522 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9524 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9527 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9532 ec.Report.Error (233, loc,
9533 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9534 type_queried.GetSignatureForError ());
9537 type = ec.BuiltinTypes.Int;
9538 eclass = ExprClass.Value;
9542 public override void Emit (EmitContext ec)
9544 ec.Emit (OpCodes.Sizeof, type_queried);
9547 protected override void CloneTo (CloneContext clonectx, Expression t)
9551 public override object Accept (StructuralVisitor visitor)
9553 return visitor.Visit (this);
9558 /// Implements the qualified-alias-member (::) expression.
9560 public class QualifiedAliasMember : MemberAccess
9562 readonly string alias;
9563 public static readonly string GlobalAlias = "global";
9565 public QualifiedAliasMember (string alias, string identifier, Location l)
9566 : base (null, identifier, l)
9571 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9572 : base (null, identifier, targs, l)
9577 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9578 : base (null, identifier, arity, l)
9583 public string Alias {
9589 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9591 if (alias == GlobalAlias)
9592 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9594 int errors = mc.Module.Compiler.Report.Errors;
9595 var expr = mc.LookupNamespaceAlias (alias);
9597 if (errors == mc.Module.Compiler.Report.Errors)
9598 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9606 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9608 expr = CreateExpressionFromAlias (mc);
9612 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9615 protected override Expression DoResolve (ResolveContext rc)
9617 return ResolveAsTypeOrNamespace (rc, false);
9620 public override string GetSignatureForError ()
9623 if (targs != null) {
9624 name = Name + "<" + targs.GetSignatureForError () + ">";
9627 return alias + "::" + name;
9630 public override bool HasConditionalAccess ()
9635 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9637 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9638 rc.Module.Compiler.Report.Error (687, loc,
9639 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9640 GetSignatureForError ());
9645 return DoResolve (rc);
9648 protected override void CloneTo (CloneContext clonectx, Expression t)
9653 public override object Accept (StructuralVisitor visitor)
9655 return visitor.Visit (this);
9660 /// Implements the member access expression
9662 public class MemberAccess : ATypeNameExpression
9664 protected Expression expr;
9666 public MemberAccess (Expression expr, string id)
9667 : base (id, expr.Location)
9672 public MemberAccess (Expression expr, string identifier, Location loc)
9673 : base (identifier, loc)
9678 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9679 : base (identifier, args, loc)
9684 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9685 : base (identifier, arity, loc)
9690 public Expression LeftExpression {
9696 public override Location StartLocation {
9698 return expr == null ? loc : expr.StartLocation;
9702 protected override Expression DoResolve (ResolveContext rc)
9704 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9706 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9711 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9713 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9715 if (e is TypeExpr) {
9716 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9721 e = e.ResolveLValue (rc, rhs);
9726 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9728 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9729 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9731 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9734 public override bool HasConditionalAccess ()
9736 return LeftExpression.HasConditionalAccess ();
9739 public static bool IsValidDotExpression (TypeSpec type)
9741 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9742 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9744 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9747 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9749 var sn = expr as SimpleName;
9750 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9753 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9756 // Resolve expression which does have type set as we need expression type
9757 // with disable flow analysis as we don't know whether left side expression
9758 // is used as variable or type
9760 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9761 expr = expr.Resolve (rc);
9762 } else if (expr is TypeParameterExpr) {
9763 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9767 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9768 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9769 expr = expr.Resolve (rc, flags);
9772 expr = expr.Resolve (rc, flags);
9779 var ns = expr as NamespaceExpression;
9781 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9783 if (retval == null) {
9784 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9789 if (HasTypeArguments)
9790 return new GenericTypeExpr (retval.Type, targs, loc);
9792 targs.Resolve (rc, false);
9798 var cma = this as ConditionalMemberAccess;
9801 TypeSpec expr_type = expr.Type;
9802 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9803 me = expr as MemberExpr;
9805 me.ResolveInstanceExpression (rc, null);
9807 Arguments args = new Arguments (1);
9808 args.Add (new Argument (expr));
9811 return new DynamicConditionalMemberBinder (Name, args, loc);
9813 return new DynamicMemberBinder (Name, args, loc);
9817 if (!IsNullPropagatingValid (expr.Type)) {
9818 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9822 if (expr_type.IsNullableType) {
9823 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9824 expr_type = expr.Type;
9828 if (!IsValidDotExpression (expr_type)) {
9829 Error_OperatorCannotBeApplied (rc, expr_type);
9833 var lookup_arity = Arity;
9834 bool errorMode = false;
9835 Expression member_lookup;
9837 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9838 if (member_lookup == null) {
9840 // Try to look for extension method when member lookup failed
9842 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9843 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9844 if (methods != null) {
9845 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9846 if (HasTypeArguments) {
9847 if (!targs.Resolve (rc, false))
9850 emg.SetTypeArguments (rc, targs);
9854 emg.ConditionalAccess = true;
9856 // TODO: it should really skip the checks bellow
9857 return emg.Resolve (rc);
9863 if (member_lookup == null) {
9864 var dep = expr_type.GetMissingDependencies ();
9866 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9867 } else if (expr is TypeExpr) {
9868 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9870 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9876 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9877 // Leave it to overload resolution to report correct error
9878 } else if (!(member_lookup is TypeExpr)) {
9879 // TODO: rc.SymbolRelatedToPreviousError
9880 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9885 if (member_lookup != null)
9889 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9893 TypeExpr texpr = member_lookup as TypeExpr;
9894 if (texpr != null) {
9895 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9896 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9897 Name, texpr.GetSignatureForError ());
9900 if (!texpr.Type.IsAccessible (rc)) {
9901 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9902 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9906 if (HasTypeArguments) {
9907 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9910 return member_lookup;
9913 me = member_lookup as MemberExpr;
9915 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9920 me.ConditionalAccess = true;
9923 me = me.ResolveMemberAccess (rc, expr, sn);
9926 if (!targs.Resolve (rc, false))
9929 me.SetTypeArguments (rc, targs);
9935 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9937 FullNamedExpression fexpr = expr as FullNamedExpression;
9938 if (fexpr == null) {
9939 expr.ResolveAsType (rc);
9943 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9945 if (expr_resolved == null)
9948 var ns = expr_resolved as NamespaceExpression;
9950 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9952 if (retval == null) {
9953 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9954 } else if (Arity > 0) {
9955 if (HasTypeArguments) {
9956 retval = new GenericTypeExpr (retval.Type, targs, loc);
9957 if (retval.ResolveAsType (rc) == null)
9960 targs.Resolve (rc, allowUnboundTypeArguments);
9962 retval = new GenericOpenTypeExpr (retval.Type, loc);
9969 var tnew_expr = expr_resolved.ResolveAsType (rc);
9970 if (tnew_expr == null)
9973 TypeSpec expr_type = tnew_expr;
9974 if (TypeManager.IsGenericParameter (expr_type)) {
9975 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9976 tnew_expr.GetSignatureForError ());
9980 var qam = this as QualifiedAliasMember;
9982 rc.Module.Compiler.Report.Error (431, loc,
9983 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9988 TypeSpec nested = null;
9989 while (expr_type != null) {
9990 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9991 if (nested == null) {
9992 if (expr_type == tnew_expr) {
9993 Error_IdentifierNotFound (rc, expr_type);
9997 expr_type = tnew_expr;
9998 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9999 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10003 if (nested.IsAccessible (rc))
10007 // Keep looking after inaccessible candidate but only if
10008 // we are not in same context as the definition itself
10010 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10013 expr_type = expr_type.BaseType;
10018 if (HasTypeArguments) {
10019 texpr = new GenericTypeExpr (nested, targs, loc);
10021 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10023 texpr = new GenericOpenTypeExpr (nested, loc);
10025 } else if (expr_resolved is GenericOpenTypeExpr) {
10026 texpr = new GenericOpenTypeExpr (nested, loc);
10028 texpr = new TypeExpression (nested, loc);
10031 if (texpr.ResolveAsType (rc) == null)
10037 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10039 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10041 if (nested != null) {
10042 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10046 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10047 if (any_other_member != null) {
10048 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10052 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10053 Name, expr_type.GetSignatureForError ());
10056 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10058 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10061 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10063 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10064 ec.Report.SymbolRelatedToPreviousError (type);
10066 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10068 // a using directive or an assembly reference
10069 if (cand != null) {
10070 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10072 missing = "an assembly reference";
10075 ec.Report.Error (1061, loc,
10076 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10077 type.GetSignatureForError (), name, missing);
10081 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10084 public override string GetSignatureForError ()
10086 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10089 protected override void CloneTo (CloneContext clonectx, Expression t)
10091 MemberAccess target = (MemberAccess) t;
10093 target.expr = expr.Clone (clonectx);
10096 public override object Accept (StructuralVisitor visitor)
10098 return visitor.Visit (this);
10102 public class ConditionalMemberAccess : MemberAccess
10104 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10105 : base (expr, identifier, args, loc)
10109 public override bool HasConditionalAccess ()
10116 /// Implements checked expressions
10118 public class CheckedExpr : Expression {
10120 public Expression Expr;
10122 public CheckedExpr (Expression e, Location l)
10128 public override bool ContainsEmitWithAwait ()
10130 return Expr.ContainsEmitWithAwait ();
10133 public override Expression CreateExpressionTree (ResolveContext ec)
10135 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10136 return Expr.CreateExpressionTree (ec);
10139 protected override Expression DoResolve (ResolveContext ec)
10141 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10142 Expr = Expr.Resolve (ec);
10147 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10150 eclass = Expr.eclass;
10155 public override void Emit (EmitContext ec)
10157 using (ec.With (EmitContext.Options.CheckedScope, true))
10161 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10163 using (ec.With (EmitContext.Options.CheckedScope, true))
10164 Expr.EmitBranchable (ec, target, on_true);
10167 public override void FlowAnalysis (FlowAnalysisContext fc)
10169 Expr.FlowAnalysis (fc);
10172 public override SLE.Expression MakeExpression (BuilderContext ctx)
10174 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10175 return Expr.MakeExpression (ctx);
10179 protected override void CloneTo (CloneContext clonectx, Expression t)
10181 CheckedExpr target = (CheckedExpr) t;
10183 target.Expr = Expr.Clone (clonectx);
10186 public override object Accept (StructuralVisitor visitor)
10188 return visitor.Visit (this);
10193 /// Implements the unchecked expression
10195 public class UnCheckedExpr : Expression {
10197 public Expression Expr;
10199 public UnCheckedExpr (Expression e, Location l)
10205 public override bool ContainsEmitWithAwait ()
10207 return Expr.ContainsEmitWithAwait ();
10210 public override Expression CreateExpressionTree (ResolveContext ec)
10212 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10213 return Expr.CreateExpressionTree (ec);
10216 protected override Expression DoResolve (ResolveContext ec)
10218 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10219 Expr = Expr.Resolve (ec);
10224 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10227 eclass = Expr.eclass;
10232 public override void Emit (EmitContext ec)
10234 using (ec.With (EmitContext.Options.CheckedScope, false))
10238 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10240 using (ec.With (EmitContext.Options.CheckedScope, false))
10241 Expr.EmitBranchable (ec, target, on_true);
10244 public override void FlowAnalysis (FlowAnalysisContext fc)
10246 Expr.FlowAnalysis (fc);
10249 protected override void CloneTo (CloneContext clonectx, Expression t)
10251 UnCheckedExpr target = (UnCheckedExpr) t;
10253 target.Expr = Expr.Clone (clonectx);
10256 public override object Accept (StructuralVisitor visitor)
10258 return visitor.Visit (this);
10263 /// An Element Access expression.
10265 /// During semantic analysis these are transformed into
10266 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10268 public class ElementAccess : Expression
10270 public Arguments Arguments;
10271 public Expression Expr;
10272 bool conditional_access_receiver;
10274 public ElementAccess (Expression e, Arguments args, Location loc)
10278 this.Arguments = args;
10281 public bool ConditionalAccess { get; set; }
10283 public override Location StartLocation {
10285 return Expr.StartLocation;
10289 public override bool ContainsEmitWithAwait ()
10291 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10295 // We perform some simple tests, and then to "split" the emit and store
10296 // code we create an instance of a different class, and return that.
10298 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10300 if (conditionalAccessReceiver)
10301 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10303 Expr = Expr.Resolve (ec);
10305 if (conditionalAccessReceiver)
10306 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10313 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10314 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10318 if (type.IsArray) {
10319 var aa = new ArrayAccess (this, loc) {
10320 ConditionalAccess = ConditionalAccess,
10323 if (conditionalAccessReceiver)
10324 aa.SetConditionalAccessReceiver ();
10329 if (type.IsPointer)
10330 return Expr.MakePointerAccess (ec, type, Arguments);
10332 FieldExpr fe = Expr as FieldExpr;
10334 var ff = fe.Spec as FixedFieldSpec;
10336 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10340 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10341 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10342 var indexer = new IndexerExpr (indexers, type, this) {
10343 ConditionalAccess = ConditionalAccess
10346 if (conditionalAccessReceiver)
10347 indexer.SetConditionalAccessReceiver ();
10352 Error_CannotApplyIndexing (ec, type, loc);
10357 public override Expression CreateExpressionTree (ResolveContext ec)
10359 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10360 Expr.CreateExpressionTree (ec));
10362 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10365 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10367 if (type != InternalType.ErrorType) {
10368 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10369 type.GetSignatureForError ());
10373 public override bool HasConditionalAccess ()
10375 return ConditionalAccess || Expr.HasConditionalAccess ();
10378 void ResolveConditionalAccessReceiver (ResolveContext rc)
10380 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10381 conditional_access_receiver = true;
10385 protected override Expression DoResolve (ResolveContext rc)
10387 ResolveConditionalAccessReceiver (rc);
10389 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10393 return expr.Resolve (rc);
10396 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10398 var res = CreateAccessExpression (ec, false);
10402 return res.ResolveLValue (ec, rhs);
10405 public override void Emit (EmitContext ec)
10407 throw new Exception ("Should never be reached");
10410 public override void FlowAnalysis (FlowAnalysisContext fc)
10412 Expr.FlowAnalysis (fc);
10414 Arguments.FlowAnalysis (fc);
10417 public override string GetSignatureForError ()
10419 return Expr.GetSignatureForError ();
10422 protected override void CloneTo (CloneContext clonectx, Expression t)
10424 ElementAccess target = (ElementAccess) t;
10426 target.Expr = Expr.Clone (clonectx);
10427 if (Arguments != null)
10428 target.Arguments = Arguments.Clone (clonectx);
10431 public override object Accept (StructuralVisitor visitor)
10433 return visitor.Visit (this);
10438 /// Implements array access
10440 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10442 // Points to our "data" repository
10446 LocalTemporary temp;
10448 bool? has_await_args;
10449 bool conditional_access_receiver;
10451 public ArrayAccess (ElementAccess ea_data, Location l)
10457 public bool ConditionalAccess { get; set; }
10459 public void AddressOf (EmitContext ec, AddressOp mode)
10461 var ac = (ArrayContainer) ea.Expr.Type;
10463 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10464 LoadInstanceAndArguments (ec, false, true);
10467 LoadInstanceAndArguments (ec, false, false);
10469 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10470 ec.Emit (OpCodes.Readonly);
10472 ec.EmitArrayAddress (ac);
10475 public override Expression CreateExpressionTree (ResolveContext ec)
10477 if (ConditionalAccess)
10478 Error_NullShortCircuitInsideExpressionTree (ec);
10480 return ea.CreateExpressionTree (ec);
10483 public override bool ContainsEmitWithAwait ()
10485 return ea.ContainsEmitWithAwait ();
10488 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10490 if (HasConditionalAccess ())
10491 Error_NullPropagatingLValue (ec);
10493 return DoResolve (ec);
10496 protected override Expression DoResolve (ResolveContext ec)
10498 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10500 ea.Arguments.Resolve (ec, out dynamic);
10502 var ac = ea.Expr.Type as ArrayContainer;
10503 int rank = ea.Arguments.Count;
10504 if (ac.Rank != rank) {
10505 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10506 rank.ToString (), ac.Rank.ToString ());
10511 if (type.IsPointer) {
10512 if (ec.CurrentIterator != null) {
10513 UnsafeInsideIteratorError (ec, ea.Location);
10514 } else if (!ec.IsUnsafe) {
10515 UnsafeError (ec, ea.Location);
10519 if (conditional_access_receiver)
10520 type = LiftMemberType (ec, type);
10522 foreach (Argument a in ea.Arguments) {
10523 var na = a as NamedArgument;
10525 ElementAccess.Error_NamedArgument (na, ec.Report);
10527 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10530 eclass = ExprClass.Variable;
10535 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10537 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10540 public override void FlowAnalysis (FlowAnalysisContext fc)
10542 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10544 ea.FlowAnalysis (fc);
10546 if (conditional_access_receiver)
10547 fc.DefiniteAssignment = da;
10550 public override bool HasConditionalAccess ()
10552 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10556 // Load the array arguments into the stack.
10558 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10560 if (prepareAwait) {
10561 ea.Expr = ea.Expr.EmitToField (ec);
10563 var ie = new InstanceEmitter (ea.Expr, false);
10564 ie.Emit (ec, ConditionalAccess);
10566 if (duplicateArguments) {
10567 ec.Emit (OpCodes.Dup);
10569 var copy = new LocalTemporary (ea.Expr.Type);
10575 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10576 if (dup_args != null)
10577 ea.Arguments = dup_args;
10580 public void Emit (EmitContext ec, bool leave_copy)
10583 ec.EmitLoadFromPtr (type);
10585 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10586 LoadInstanceAndArguments (ec, false, true);
10589 if (conditional_access_receiver)
10590 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10592 var ac = (ArrayContainer) ea.Expr.Type;
10593 LoadInstanceAndArguments (ec, false, false);
10594 ec.EmitArrayLoad (ac);
10596 if (conditional_access_receiver)
10597 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10601 ec.Emit (OpCodes.Dup);
10602 temp = new LocalTemporary (this.type);
10607 public override void Emit (EmitContext ec)
10612 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10614 var ac = (ArrayContainer) ea.Expr.Type;
10615 TypeSpec t = source.Type;
10617 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10620 // When we are dealing with a struct, get the address of it to avoid value copy
10621 // Same cannot be done for reference type because array covariance and the
10622 // check in ldelema requires to specify the type of array element stored at the index
10624 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10625 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10627 if (has_await_args.Value) {
10628 if (source.ContainsEmitWithAwait ()) {
10629 source = source.EmitToField (ec);
10630 isCompound = false;
10634 LoadInstanceAndArguments (ec, isCompound, false);
10639 ec.EmitArrayAddress (ac);
10642 ec.Emit (OpCodes.Dup);
10646 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10648 if (has_await_args.Value) {
10649 if (source.ContainsEmitWithAwait ())
10650 source = source.EmitToField (ec);
10652 LoadInstanceAndArguments (ec, false, false);
10659 var lt = ea.Expr as LocalTemporary;
10665 ec.Emit (OpCodes.Dup);
10666 temp = new LocalTemporary (this.type);
10671 ec.EmitStoreFromPtr (t);
10673 ec.EmitArrayStore (ac);
10676 if (temp != null) {
10682 public override Expression EmitToField (EmitContext ec)
10685 // Have to be specialized for arrays to get access to
10686 // underlying element. Instead of another result copy we
10687 // need direct access to element
10691 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10693 ea.Expr = ea.Expr.EmitToField (ec);
10694 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10698 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10700 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10703 public override SLE.Expression MakeExpression (BuilderContext ctx)
10705 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10708 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10710 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10711 return Arguments.MakeExpression (ea.Arguments, ctx);
10715 public void SetConditionalAccessReceiver ()
10717 conditional_access_receiver = true;
10722 // Indexer access expression
10724 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10726 IList<MemberSpec> indexers;
10727 Arguments arguments;
10728 TypeSpec queried_type;
10730 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10731 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10735 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10738 this.indexers = indexers;
10739 this.queried_type = queriedType;
10740 this.InstanceExpression = instance;
10741 this.arguments = args;
10746 protected override Arguments Arguments {
10755 protected override TypeSpec DeclaringType {
10757 return best_candidate.DeclaringType;
10761 public override bool IsInstance {
10767 public override bool IsStatic {
10773 public override string KindName {
10774 get { return "indexer"; }
10777 public override string Name {
10785 public override bool ContainsEmitWithAwait ()
10787 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10790 public override Expression CreateExpressionTree (ResolveContext ec)
10792 if (ConditionalAccess) {
10793 Error_NullShortCircuitInsideExpressionTree (ec);
10796 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10797 InstanceExpression.CreateExpressionTree (ec),
10798 new TypeOfMethod (Getter, loc));
10800 return CreateExpressionFactoryCall (ec, "Call", args);
10803 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10805 LocalTemporary await_source_arg = null;
10808 emitting_compound_assignment = true;
10809 if (source is DynamicExpressionStatement) {
10814 emitting_compound_assignment = false;
10816 if (has_await_arguments) {
10817 await_source_arg = new LocalTemporary (Type);
10818 await_source_arg.Store (ec);
10820 arguments.Add (new Argument (await_source_arg));
10823 temp = await_source_arg;
10826 has_await_arguments = false;
10831 ec.Emit (OpCodes.Dup);
10832 temp = new LocalTemporary (Type);
10838 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10839 source = source.EmitToField (ec);
10841 temp = new LocalTemporary (Type);
10848 arguments.Add (new Argument (source));
10851 var call = new CallEmitter ();
10852 call.InstanceExpression = InstanceExpression;
10853 if (arguments == null)
10854 call.InstanceExpressionOnStack = true;
10856 call.Emit (ec, Setter, arguments, loc);
10858 if (temp != null) {
10861 } else if (leave_copy) {
10865 if (await_source_arg != null) {
10866 await_source_arg.Release (ec);
10870 public override void FlowAnalysis (FlowAnalysisContext fc)
10872 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10874 base.FlowAnalysis (fc);
10875 arguments.FlowAnalysis (fc);
10877 if (conditional_access_receiver)
10878 fc.DefiniteAssignment = da;
10881 public override string GetSignatureForError ()
10883 return best_candidate.GetSignatureForError ();
10886 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10889 throw new NotSupportedException ();
10891 var value = new[] { source.MakeExpression (ctx) };
10892 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10893 return SLE.Expression.Block (
10894 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10899 public override SLE.Expression MakeExpression (BuilderContext ctx)
10902 return base.MakeExpression (ctx);
10904 var args = Arguments.MakeExpression (arguments, ctx);
10905 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10909 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10911 if (best_candidate != null)
10914 eclass = ExprClass.IndexerAccess;
10917 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10918 arguments.Resolve (rc, out dynamic);
10921 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10924 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10925 res.BaseMembersProvider = this;
10926 res.InstanceQualifier = this;
10928 // TODO: Do I need 2 argument sets?
10929 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10930 if (best_candidate != null)
10931 type = res.BestCandidateReturnType;
10932 else if (!res.BestCandidateIsDynamic)
10937 // It has dynamic arguments
10940 Arguments args = new Arguments (arguments.Count + 1);
10942 rc.Report.Error (1972, loc,
10943 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10945 args.Add (new Argument (InstanceExpression));
10947 args.AddRange (arguments);
10949 best_candidate = null;
10950 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10954 // Try to avoid resolving left expression again
10956 if (right_side != null)
10957 ResolveInstanceExpression (rc, right_side);
10962 protected override void CloneTo (CloneContext clonectx, Expression t)
10964 IndexerExpr target = (IndexerExpr) t;
10966 if (arguments != null)
10967 target.arguments = arguments.Clone (clonectx);
10970 public void SetConditionalAccessReceiver ()
10972 conditional_access_receiver = true;
10975 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10977 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10980 #region IBaseMembersProvider Members
10982 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
10984 var baseType = type.BaseType;
10985 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10987 if (members == null && !type.IsInterface) {
10988 var tps = queried_type as TypeParameterSpec;
10990 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
10996 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10998 if (queried_type == member.DeclaringType)
11001 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11002 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11005 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11014 // A base access expression
11016 public class BaseThis : This
11018 public BaseThis (Location loc)
11023 public BaseThis (TypeSpec type, Location loc)
11027 eclass = ExprClass.Variable;
11032 public override string Name {
11040 public override Expression CreateExpressionTree (ResolveContext ec)
11042 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11043 return base.CreateExpressionTree (ec);
11046 public override void Emit (EmitContext ec)
11050 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11051 var context_type = ec.CurrentType;
11052 ec.Emit (OpCodes.Ldobj, context_type);
11053 ec.Emit (OpCodes.Box, context_type);
11057 protected override void Error_ThisNotAvailable (ResolveContext ec)
11060 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11062 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11066 public override void ResolveBase (ResolveContext ec)
11068 base.ResolveBase (ec);
11069 type = ec.CurrentType.BaseType;
11072 public override object Accept (StructuralVisitor visitor)
11074 return visitor.Visit (this);
11079 /// This class exists solely to pass the Type around and to be a dummy
11080 /// that can be passed to the conversion functions (this is used by
11081 /// foreach implementation to typecast the object return value from
11082 /// get_Current into the proper type. All code has been generated and
11083 /// we only care about the side effect conversions to be performed
11085 /// This is also now used as a placeholder where a no-action expression
11086 /// is needed (the `New' class).
11088 public class EmptyExpression : Expression
11090 sealed class OutAccessExpression : EmptyExpression
11092 public OutAccessExpression (TypeSpec t)
11097 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11099 rc.Report.Error (206, right_side.Location,
11100 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11106 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11107 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11108 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11109 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11110 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11111 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11112 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11113 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11115 public EmptyExpression (TypeSpec t)
11118 eclass = ExprClass.Value;
11119 loc = Location.Null;
11122 protected override void CloneTo (CloneContext clonectx, Expression target)
11126 public override bool ContainsEmitWithAwait ()
11131 public override Expression CreateExpressionTree (ResolveContext ec)
11133 throw new NotSupportedException ("ET");
11136 protected override Expression DoResolve (ResolveContext ec)
11141 public override void Emit (EmitContext ec)
11143 // nothing, as we only exist to not do anything.
11146 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11150 public override void EmitSideEffect (EmitContext ec)
11154 public override object Accept (StructuralVisitor visitor)
11156 return visitor.Visit (this);
11160 sealed class EmptyAwaitExpression : EmptyExpression
11162 public EmptyAwaitExpression (TypeSpec type)
11167 public override bool ContainsEmitWithAwait ()
11174 // Empty statement expression
11176 public sealed class EmptyExpressionStatement : ExpressionStatement
11178 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11180 private EmptyExpressionStatement ()
11182 loc = Location.Null;
11185 public override bool ContainsEmitWithAwait ()
11190 public override Expression CreateExpressionTree (ResolveContext ec)
11195 public override void EmitStatement (EmitContext ec)
11200 protected override Expression DoResolve (ResolveContext ec)
11202 eclass = ExprClass.Value;
11203 type = ec.BuiltinTypes.Object;
11207 public override void Emit (EmitContext ec)
11212 public override object Accept (StructuralVisitor visitor)
11214 return visitor.Visit (this);
11218 public class ErrorExpression : EmptyExpression
11220 public static readonly ErrorExpression Instance = new ErrorExpression ();
11222 private ErrorExpression ()
11223 : base (InternalType.ErrorType)
11227 public override Expression CreateExpressionTree (ResolveContext ec)
11232 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11237 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11241 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11245 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11249 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11253 public override object Accept (StructuralVisitor visitor)
11255 return visitor.Visit (this);
11259 public class UserCast : Expression {
11263 public UserCast (MethodSpec method, Expression source, Location l)
11265 if (source == null)
11266 throw new ArgumentNullException ("source");
11268 this.method = method;
11269 this.source = source;
11270 type = method.ReturnType;
11274 public Expression Source {
11283 public override bool ContainsEmitWithAwait ()
11285 return source.ContainsEmitWithAwait ();
11288 public override Expression CreateExpressionTree (ResolveContext ec)
11290 Arguments args = new Arguments (3);
11291 args.Add (new Argument (source.CreateExpressionTree (ec)));
11292 args.Add (new Argument (new TypeOf (type, loc)));
11293 args.Add (new Argument (new TypeOfMethod (method, loc)));
11294 return CreateExpressionFactoryCall (ec, "Convert", args);
11297 protected override Expression DoResolve (ResolveContext ec)
11299 method.CheckObsoleteness (ec, source.Location);
11301 eclass = ExprClass.Value;
11305 public override void Emit (EmitContext ec)
11308 ec.MarkCallEntry (loc);
11309 ec.Emit (OpCodes.Call, method);
11312 public override void FlowAnalysis (FlowAnalysisContext fc)
11314 source.FlowAnalysis (fc);
11317 public override string GetSignatureForError ()
11319 return TypeManager.CSharpSignature (method);
11322 public override SLE.Expression MakeExpression (BuilderContext ctx)
11325 return base.MakeExpression (ctx);
11327 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11333 // Holds additional type specifiers like ?, *, []
11335 public class ComposedTypeSpecifier
11337 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11339 public readonly int Dimension;
11340 public readonly Location Location;
11342 public ComposedTypeSpecifier (int specifier, Location loc)
11344 this.Dimension = specifier;
11345 this.Location = loc;
11349 public bool IsNullable {
11351 return Dimension == -1;
11355 public bool IsPointer {
11357 return Dimension == -2;
11361 public ComposedTypeSpecifier Next { get; set; }
11365 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11367 return new ComposedTypeSpecifier (dimension, loc);
11370 public static ComposedTypeSpecifier CreateNullable (Location loc)
11372 return new ComposedTypeSpecifier (-1, loc);
11375 public static ComposedTypeSpecifier CreatePointer (Location loc)
11377 return new ComposedTypeSpecifier (-2, loc);
11380 public string GetSignatureForError ()
11385 ArrayContainer.GetPostfixSignature (Dimension);
11387 return Next != null ? s + Next.GetSignatureForError () : s;
11392 // This class is used to "construct" the type during a typecast
11393 // operation. Since the Type.GetType class in .NET can parse
11394 // the type specification, we just use this to construct the type
11395 // one bit at a time.
11397 public class ComposedCast : TypeExpr {
11398 FullNamedExpression left;
11399 ComposedTypeSpecifier spec;
11401 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11404 throw new ArgumentNullException ("spec");
11408 this.loc = left.Location;
11411 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11413 type = left.ResolveAsType (ec);
11417 eclass = ExprClass.Type;
11419 var single_spec = spec;
11421 if (single_spec.IsNullable) {
11422 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11426 single_spec = single_spec.Next;
11427 } else if (single_spec.IsPointer) {
11429 // Declared fields cannot have unmanaged check done before all types are defined
11431 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11434 var rc = ec as ResolveContext;
11435 if (rc?.CurrentIterator != null) {
11436 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11437 } else if (!ec.IsUnsafe) {
11438 UnsafeError (ec.Module.Compiler.Report, loc);
11442 type = PointerContainer.MakeType (ec.Module, type);
11443 single_spec = single_spec.Next;
11444 } while (single_spec != null && single_spec.IsPointer);
11447 if (single_spec != null && single_spec.Dimension > 0) {
11448 if (type.IsSpecialRuntimeType) {
11449 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11450 } else if (type.IsStatic) {
11451 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11452 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11453 type.GetSignatureForError ());
11455 MakeArray (ec.Module, single_spec);
11462 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11464 if (spec.Next != null)
11465 MakeArray (module, spec.Next);
11467 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11470 public override string GetSignatureForError ()
11472 return left.GetSignatureForError () + spec.GetSignatureForError ();
11475 public override object Accept (StructuralVisitor visitor)
11477 return visitor.Visit (this);
11481 class FixedBufferPtr : Expression
11483 readonly Expression array;
11485 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11487 this.type = array_type;
11488 this.array = array;
11492 public override bool ContainsEmitWithAwait ()
11494 throw new NotImplementedException ();
11497 public override Expression CreateExpressionTree (ResolveContext ec)
11499 Error_PointerInsideExpressionTree (ec);
11503 public override void Emit(EmitContext ec)
11508 protected override Expression DoResolve (ResolveContext ec)
11510 type = PointerContainer.MakeType (ec.Module, type);
11511 eclass = ExprClass.Value;
11518 // This class is used to represent the address of an array, used
11519 // only by the Fixed statement, this generates "&a [0]" construct
11520 // for fixed (char *pa = a)
11522 class ArrayPtr : FixedBufferPtr
11524 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11525 base (array, array_type, l)
11529 public override void Emit (EmitContext ec)
11534 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11539 // Encapsulates a conversion rules required for array indexes
11541 public class ArrayIndexCast : TypeCast
11543 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11544 : base (expr, returnType)
11546 if (expr.Type == returnType) // int -> int
11547 throw new ArgumentException ("unnecessary array index conversion");
11550 public override Expression CreateExpressionTree (ResolveContext ec)
11552 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11553 return base.CreateExpressionTree (ec);
11557 public override void Emit (EmitContext ec)
11561 switch (child.Type.BuiltinType) {
11562 case BuiltinTypeSpec.Type.UInt:
11563 ec.Emit (OpCodes.Conv_U);
11565 case BuiltinTypeSpec.Type.Long:
11566 ec.Emit (OpCodes.Conv_Ovf_I);
11568 case BuiltinTypeSpec.Type.ULong:
11569 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11572 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11578 // Implements the `stackalloc' keyword
11580 public class StackAlloc : Expression {
11585 public StackAlloc (Expression type, Expression count, Location l)
11588 this.count = count;
11592 public Expression TypeExpression {
11598 public Expression CountExpression {
11604 public override bool ContainsEmitWithAwait ()
11609 public override Expression CreateExpressionTree (ResolveContext ec)
11611 throw new NotSupportedException ("ET");
11614 protected override Expression DoResolve (ResolveContext ec)
11616 count = count.Resolve (ec);
11620 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11621 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11626 Constant c = count as Constant;
11627 if (c != null && c.IsNegative) {
11628 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11631 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11632 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11635 otype = texpr.ResolveAsType (ec);
11639 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11642 type = PointerContainer.MakeType (ec.Module, otype);
11643 eclass = ExprClass.Value;
11648 public override void Emit (EmitContext ec)
11650 int size = BuiltinTypeSpec.GetSize (otype);
11655 ec.Emit (OpCodes.Sizeof, otype);
11659 ec.Emit (OpCodes.Mul_Ovf_Un);
11660 ec.Emit (OpCodes.Localloc);
11663 protected override void CloneTo (CloneContext clonectx, Expression t)
11665 StackAlloc target = (StackAlloc) t;
11666 target.count = count.Clone (clonectx);
11667 target.texpr = texpr.Clone (clonectx);
11670 public override object Accept (StructuralVisitor visitor)
11672 return visitor.Visit (this);
11677 // An object initializer expression
11679 public class ElementInitializer : Assign
11681 public readonly string Name;
11683 public ElementInitializer (string name, Expression initializer, Location loc)
11684 : base (null, initializer, loc)
11689 public bool IsDictionaryInitializer {
11691 return Name == null;
11695 protected override void CloneTo (CloneContext clonectx, Expression t)
11697 ElementInitializer target = (ElementInitializer) t;
11698 target.source = source.Clone (clonectx);
11701 public override Expression CreateExpressionTree (ResolveContext ec)
11703 Arguments args = new Arguments (2);
11704 FieldExpr fe = target as FieldExpr;
11706 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11708 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11711 Expression arg_expr;
11712 var cinit = source as CollectionOrObjectInitializers;
11713 if (cinit == null) {
11715 arg_expr = source.CreateExpressionTree (ec);
11717 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11718 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11721 args.Add (new Argument (arg_expr));
11722 return CreateExpressionFactoryCall (ec, mname, args);
11725 protected override Expression DoResolve (ResolveContext ec)
11727 if (source == null)
11728 return EmptyExpressionStatement.Instance;
11730 if (!ResolveElement (ec))
11733 if (source is CollectionOrObjectInitializers) {
11734 target = target.Resolve (ec);
11735 if (target == null)
11738 Expression previous = ec.CurrentInitializerVariable;
11739 ec.CurrentInitializerVariable = target;
11740 source = source.Resolve (ec);
11741 ec.CurrentInitializerVariable = previous;
11742 if (source == null)
11745 eclass = source.eclass;
11746 type = source.Type;
11751 return base.DoResolve (ec);
11754 public override void EmitStatement (EmitContext ec)
11756 if (source is CollectionOrObjectInitializers)
11759 base.EmitStatement (ec);
11762 protected virtual bool ResolveElement (ResolveContext rc)
11764 var t = rc.CurrentInitializerVariable.Type;
11765 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11766 Arguments args = new Arguments (1);
11767 args.Add (new Argument (rc.CurrentInitializerVariable));
11768 target = new DynamicMemberBinder (Name, args, loc);
11770 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11771 if (member == null) {
11772 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11774 if (member != null) {
11775 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11776 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11781 if (member == null) {
11782 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11786 var me = member as MemberExpr;
11787 if (me is EventExpr) {
11788 me = me.ResolveMemberAccess (rc, null, null);
11789 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11790 rc.Report.Error (1913, loc,
11791 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11792 member.GetSignatureForError ());
11798 rc.Report.Error (1914, loc,
11799 "Static field or property `{0}' cannot be assigned in an object initializer",
11800 me.GetSignatureForError ());
11804 me.InstanceExpression = rc.CurrentInitializerVariable;
11812 // A collection initializer expression
11814 class CollectionElementInitializer : Invocation
11816 public class ElementInitializerArgument : Argument
11818 public ElementInitializerArgument (Expression e)
11824 sealed class AddMemberAccess : MemberAccess
11826 public AddMemberAccess (Expression expr, Location loc)
11827 : base (expr, "Add", loc)
11831 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11833 if (TypeManager.HasElementType (type))
11836 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11840 public CollectionElementInitializer (Expression argument)
11841 : base (null, new Arguments (1))
11843 base.arguments.Add (new ElementInitializerArgument (argument));
11844 this.loc = argument.Location;
11847 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11848 : base (null, new Arguments (arguments.Count))
11850 foreach (Expression e in arguments)
11851 base.arguments.Add (new ElementInitializerArgument (e));
11856 public CollectionElementInitializer (Location loc)
11857 : base (null, null)
11862 public override Expression CreateExpressionTree (ResolveContext ec)
11864 Arguments args = new Arguments (2);
11865 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11867 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11868 foreach (Argument a in arguments) {
11869 if (a.ArgType == Argument.AType.ExtensionType) {
11870 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11873 expr_initializers.Add (a.CreateExpressionTree (ec));
11876 args.Add (new Argument (new ArrayCreation (
11877 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11878 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11881 protected override void CloneTo (CloneContext clonectx, Expression t)
11883 CollectionElementInitializer target = (CollectionElementInitializer) t;
11884 if (arguments != null)
11885 target.arguments = arguments.Clone (clonectx);
11888 protected override Expression DoResolve (ResolveContext ec)
11890 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11892 return base.DoResolve (ec);
11896 class DictionaryElementInitializer : ElementInitializer
11898 readonly Arguments args;
11900 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11901 : base (null, initializer, loc)
11903 this.args = arguments;
11906 public override Expression CreateExpressionTree (ResolveContext ec)
11908 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11912 protected override bool ResolveElement (ResolveContext rc)
11914 var init = rc.CurrentInitializerVariable;
11915 var type = init.Type;
11917 if (type.IsArray) {
11918 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11922 if (type.IsPointer) {
11923 target = init.MakePointerAccess (rc, type, args);
11927 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11928 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11929 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11933 target = new IndexerExpr (indexers, type, init, args, loc);
11939 // A block of object or collection initializers
11941 public class CollectionOrObjectInitializers : ExpressionStatement
11943 IList<Expression> initializers;
11944 bool is_collection_initialization;
11946 public CollectionOrObjectInitializers (Location loc)
11947 : this (new Expression[0], loc)
11951 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11953 this.initializers = initializers;
11957 public IList<Expression> Initializers {
11959 return initializers;
11963 public bool IsEmpty {
11965 return initializers.Count == 0;
11969 public bool IsCollectionInitializer {
11971 return is_collection_initialization;
11975 protected override void CloneTo (CloneContext clonectx, Expression target)
11977 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11979 t.initializers = new List<Expression> (initializers.Count);
11980 foreach (var e in initializers)
11981 t.initializers.Add (e.Clone (clonectx));
11984 public override bool ContainsEmitWithAwait ()
11986 foreach (var e in initializers) {
11987 if (e.ContainsEmitWithAwait ())
11994 public override Expression CreateExpressionTree (ResolveContext ec)
11996 return CreateExpressionTree (ec, false);
11999 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12001 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12002 foreach (Expression e in initializers) {
12003 Expression expr = e.CreateExpressionTree (ec);
12005 expr_initializers.Add (expr);
12009 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12011 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12014 protected override Expression DoResolve (ResolveContext ec)
12016 List<string> element_names = null;
12017 for (int i = 0; i < initializers.Count; ++i) {
12018 Expression initializer = initializers [i];
12019 ElementInitializer element_initializer = initializer as ElementInitializer;
12022 if (element_initializer != null) {
12023 element_names = new List<string> (initializers.Count);
12024 if (!element_initializer.IsDictionaryInitializer)
12025 element_names.Add (element_initializer.Name);
12026 } else if (initializer is CompletingExpression) {
12027 initializer.Resolve (ec);
12028 throw new InternalErrorException ("This line should never be reached");
12030 var t = ec.CurrentInitializerVariable.Type;
12031 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12032 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12033 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12034 "object initializer because type `{1}' does not implement `{2}' interface",
12035 ec.CurrentInitializerVariable.GetSignatureForError (),
12036 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12037 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12040 is_collection_initialization = true;
12043 if (is_collection_initialization != (element_initializer == null)) {
12044 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12045 is_collection_initialization ? "collection initializer" : "object initializer");
12049 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12050 if (element_names.Contains (element_initializer.Name)) {
12051 ec.Report.Error (1912, element_initializer.Location,
12052 "An object initializer includes more than one member `{0}' initialization",
12053 element_initializer.Name);
12055 element_names.Add (element_initializer.Name);
12060 Expression e = initializer.Resolve (ec);
12061 if (e == EmptyExpressionStatement.Instance)
12062 initializers.RemoveAt (i--);
12064 initializers [i] = e;
12067 type = ec.CurrentInitializerVariable.Type;
12068 if (is_collection_initialization) {
12069 if (TypeManager.HasElementType (type)) {
12070 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12071 type.GetSignatureForError ());
12075 eclass = ExprClass.Variable;
12079 public override void Emit (EmitContext ec)
12081 EmitStatement (ec);
12084 public override void EmitStatement (EmitContext ec)
12086 foreach (ExpressionStatement e in initializers) {
12087 // TODO: need location region
12088 ec.Mark (e.Location);
12089 e.EmitStatement (ec);
12093 public override void FlowAnalysis (FlowAnalysisContext fc)
12095 foreach (var initializer in initializers) {
12096 if (initializer != null)
12097 initializer.FlowAnalysis (fc);
12103 // New expression with element/object initializers
12105 public class NewInitialize : New
12108 // This class serves as a proxy for variable initializer target instances.
12109 // A real variable is assigned later when we resolve left side of an
12112 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12114 NewInitialize new_instance;
12116 public InitializerTargetExpression (NewInitialize newInstance)
12118 this.type = newInstance.type;
12119 this.loc = newInstance.loc;
12120 this.eclass = newInstance.eclass;
12121 this.new_instance = newInstance;
12124 public override bool ContainsEmitWithAwait ()
12129 public override Expression CreateExpressionTree (ResolveContext ec)
12131 // Should not be reached
12132 throw new NotSupportedException ("ET");
12135 protected override Expression DoResolve (ResolveContext ec)
12140 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12145 public override void Emit (EmitContext ec)
12147 Expression e = (Expression) new_instance.instance;
12151 public override Expression EmitToField (EmitContext ec)
12153 return (Expression) new_instance.instance;
12156 #region IMemoryLocation Members
12158 public void AddressOf (EmitContext ec, AddressOp mode)
12160 new_instance.instance.AddressOf (ec, mode);
12166 CollectionOrObjectInitializers initializers;
12167 IMemoryLocation instance;
12168 DynamicExpressionStatement dynamic;
12170 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12171 : base (requested_type, arguments, l)
12173 this.initializers = initializers;
12176 public CollectionOrObjectInitializers Initializers {
12178 return initializers;
12182 protected override void CloneTo (CloneContext clonectx, Expression t)
12184 base.CloneTo (clonectx, t);
12186 NewInitialize target = (NewInitialize) t;
12187 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12190 public override bool ContainsEmitWithAwait ()
12192 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12195 public override Expression CreateExpressionTree (ResolveContext ec)
12197 Arguments args = new Arguments (2);
12198 args.Add (new Argument (base.CreateExpressionTree (ec)));
12199 if (!initializers.IsEmpty)
12200 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12202 return CreateExpressionFactoryCall (ec,
12203 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12207 protected override Expression DoResolve (ResolveContext rc)
12209 Expression e = base.DoResolve (rc);
12213 if (type.IsDelegate) {
12214 rc.Report.Error (1958, Initializers.Location,
12215 "Object and collection initializers cannot be used to instantiate a delegate");
12218 Expression previous = rc.CurrentInitializerVariable;
12219 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12220 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12221 initializers.Resolve (rc);
12223 rc.CurrentInitializerVariable = previous;
12225 dynamic = e as DynamicExpressionStatement;
12226 if (dynamic != null)
12232 public override void Emit (EmitContext ec)
12234 if (!CanEmitOptimizedLocalTarget (ec)) {
12235 var fe = ec.GetTemporaryField (type);
12237 if (!Emit (ec, fe))
12246 public override bool Emit (EmitContext ec, IMemoryLocation target)
12249 // Expression is initialized into temporary target then moved
12250 // to real one for atomicity
12252 IMemoryLocation temp_target = target;
12254 LocalTemporary temp = null;
12255 bool by_ref = false;
12256 if (!initializers.IsEmpty) {
12257 temp_target = target as LocalTemporary;
12258 if (temp_target == null)
12259 temp_target = target as StackFieldExpr;
12261 if (temp_target == null) {
12262 var vr = target as VariableReference;
12263 if (vr != null && vr.IsRef) {
12269 if (temp_target == null)
12270 temp_target = temp = new LocalTemporary (type);
12273 bool left_on_stack;
12274 if (dynamic != null) {
12276 left_on_stack = true;
12278 left_on_stack = base.Emit (ec, temp_target);
12281 if (initializers.IsEmpty)
12282 return left_on_stack;
12284 StackFieldExpr sf = null;
12286 // Move a new instance (reference-type) to local temporary variable
12287 if (left_on_stack) {
12289 temp_target = temp = new LocalTemporary (type);
12295 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12297 throw new NotImplementedException ();
12299 sf = ec.GetTemporaryField (type);
12300 sf.AutomaticallyReuse = false;
12301 sf.EmitAssign (ec, temp, false, false);
12304 left_on_stack = false;
12308 instance = temp_target;
12310 initializers.Emit (ec);
12312 ((Expression)temp_target).Emit (ec);
12318 sf.PrepareCleanup (ec);
12323 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12325 return !(method == null && TypeSpec.IsValueType (type) &&
12326 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12327 initializers.ContainsEmitWithAwait ());
12330 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12332 instance = base.EmitAddressOf (ec, Mode);
12334 if (!initializers.IsEmpty)
12335 initializers.Emit (ec);
12340 public override void FlowAnalysis (FlowAnalysisContext fc)
12342 base.FlowAnalysis (fc);
12343 initializers.FlowAnalysis (fc);
12346 public override object Accept (StructuralVisitor visitor)
12348 return visitor.Visit (this);
12352 public class NewAnonymousType : New
12354 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12356 List<AnonymousTypeParameter> parameters;
12357 readonly TypeContainer parent;
12358 AnonymousTypeClass anonymous_type;
12360 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12361 : base (null, null, loc)
12363 this.parameters = parameters;
12364 this.parent = parent;
12367 public List<AnonymousTypeParameter> Parameters {
12369 return this.parameters;
12373 protected override void CloneTo (CloneContext clonectx, Expression target)
12375 if (parameters == null)
12378 NewAnonymousType t = (NewAnonymousType) target;
12379 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12380 foreach (AnonymousTypeParameter atp in parameters)
12381 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12384 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12386 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12390 type = AnonymousTypeClass.Create (parent, parameters, loc);
12394 int errors = ec.Report.Errors;
12395 type.CreateContainer ();
12396 type.DefineContainer ();
12397 type.ExpandBaseInterfaces ();
12399 if ((ec.Report.Errors - errors) == 0) {
12400 parent.Module.AddAnonymousType (type);
12401 type.PrepareEmit ();
12407 public override Expression CreateExpressionTree (ResolveContext ec)
12409 if (parameters == null)
12410 return base.CreateExpressionTree (ec);
12412 var init = new ArrayInitializer (parameters.Count, loc);
12413 foreach (var m in anonymous_type.Members) {
12414 var p = m as Property;
12416 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12419 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12420 foreach (Argument a in arguments)
12421 ctor_args.Add (a.CreateExpressionTree (ec));
12423 Arguments args = new Arguments (3);
12424 args.Add (new Argument (new TypeOfMethod (method, loc)));
12425 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12426 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12428 return CreateExpressionFactoryCall (ec, "New", args);
12431 protected override Expression DoResolve (ResolveContext ec)
12433 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12434 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12438 if (parameters == null) {
12439 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12440 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12441 return base.DoResolve (ec);
12444 bool error = false;
12445 arguments = new Arguments (parameters.Count);
12446 var t_args = new TypeSpec [parameters.Count];
12447 for (int i = 0; i < parameters.Count; ++i) {
12448 Expression e = parameters [i].Resolve (ec);
12454 arguments.Add (new Argument (e));
12455 t_args [i] = e.Type;
12461 anonymous_type = CreateAnonymousType (ec, parameters);
12462 if (anonymous_type == null)
12465 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12466 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12467 eclass = ExprClass.Value;
12471 public override object Accept (StructuralVisitor visitor)
12473 return visitor.Visit (this);
12477 public class AnonymousTypeParameter : ShimExpression
12479 public readonly string Name;
12481 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12482 : base (initializer)
12488 public AnonymousTypeParameter (Parameter parameter)
12489 : base (new SimpleName (parameter.Name, parameter.Location))
12491 this.Name = parameter.Name;
12492 this.loc = parameter.Location;
12495 public override bool Equals (object o)
12497 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12498 return other != null && Name == other.Name;
12501 public override int GetHashCode ()
12503 return Name.GetHashCode ();
12506 protected override Expression DoResolve (ResolveContext ec)
12508 Expression e = expr.Resolve (ec);
12512 if (e.eclass == ExprClass.MethodGroup) {
12513 Error_InvalidInitializer (ec, e.ExprClassName);
12518 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12519 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12526 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12528 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12529 Name, initializer);
12533 public class CatchFilterExpression : BooleanExpression
12535 public CatchFilterExpression (Expression expr, Location loc)
12542 public class InterpolatedString : Expression
12544 readonly StringLiteral start, end;
12545 List<Expression> interpolations;
12546 Arguments arguments;
12548 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12550 this.start = start;
12552 this.interpolations = interpolations;
12553 loc = start.Location;
12556 protected override void CloneTo (CloneContext clonectx, Expression t)
12558 InterpolatedString target = (InterpolatedString) t;
12560 if (interpolations != null) {
12561 target.interpolations = new List<Expression> ();
12562 foreach (var interpolation in interpolations) {
12563 target.interpolations.Add (interpolation.Clone (clonectx));
12568 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12570 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12571 if (factory == null)
12574 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12575 var res = new Invocation (ma, arguments).Resolve (rc);
12576 if (res != null && res.Type != type)
12577 res = Convert.ExplicitConversion (rc, res, type, loc);
12582 public override bool ContainsEmitWithAwait ()
12584 if (interpolations == null)
12587 foreach (var expr in interpolations) {
12588 if (expr.ContainsEmitWithAwait ())
12595 public override Expression CreateExpressionTree (ResolveContext rc)
12597 var best = ResolveBestFormatOverload (rc);
12601 Expression instance = new NullLiteral (loc);
12602 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12603 return CreateExpressionFactoryCall (rc, "Call", args);
12606 protected override Expression DoResolve (ResolveContext rc)
12610 if (interpolations == null) {
12612 arguments = new Arguments (1);
12614 arguments = new Arguments (interpolations.Count);
12616 var sb = new StringBuilder (start.Value);
12617 for (int i = 0; i < interpolations.Count; ++i) {
12619 sb.Append ('{').Append (i / 2);
12620 var isi = (InterpolatedStringInsert)interpolations [i];
12621 if (isi.Alignment != null) {
12623 var value = isi.ResolveAligment (rc);
12625 sb.Append (value.Value);
12628 if (isi.Format != null) {
12630 sb.Append (isi.Format);
12634 arguments.Add (new Argument (isi.Resolve (rc)));
12636 sb.Append (((StringLiteral)interpolations [i]).Value);
12640 sb.Append (end.Value);
12641 str = sb.ToString ();
12644 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12646 eclass = ExprClass.Value;
12647 type = rc.BuiltinTypes.String;
12651 public override void Emit (EmitContext ec)
12653 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12654 if (interpolations == null) {
12655 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12656 if (str != start.Value)
12657 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12664 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12668 var ca = new CallEmitter ();
12669 ca.Emit (ec, best, arguments, loc);
12672 public override void FlowAnalysis (FlowAnalysisContext fc)
12674 if (interpolations != null) {
12675 foreach (var expr in interpolations) {
12676 expr.FlowAnalysis (fc);
12681 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12683 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12684 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12685 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12689 public class InterpolatedStringInsert : CompositeExpression
12691 public InterpolatedStringInsert (Expression expr)
12696 public Expression Alignment { get; set; }
12697 public string Format { get; set; }
12699 protected override void CloneTo (CloneContext clonectx, Expression t)
12701 var target = (InterpolatedStringInsert)t;
12702 target.expr = expr.Clone (clonectx);
12703 if (Alignment != null)
12704 target.Alignment = Alignment.Clone (clonectx);
12707 protected override Expression DoResolve (ResolveContext rc)
12709 var expr = base.DoResolve (rc);
12714 // For better error reporting, assumes the built-in implementation uses object
12717 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12720 public override void FlowAnalysis (FlowAnalysisContext fc)
12722 Child.FlowAnalysis (fc);
12725 public int? ResolveAligment (ResolveContext rc)
12727 var c = Alignment.ResolveLabelConstant (rc);
12731 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12735 var value = (int) c.GetValueAsLong ();
12736 if (value > 32767 || value < -32767) {
12737 rc.Report.Warning (8094, 1, Alignment.Location,
12738 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12745 class ThrowExpression : ExpressionStatement
12749 public ThrowExpression (Expression expr, Location loc)
12755 protected override void CloneTo (CloneContext clonectx, Expression t)
12757 var target = (ThrowExpression)t;
12758 target.expr = expr.Clone (clonectx);
12761 public override bool ContainsEmitWithAwait ()
12763 return expr.ContainsEmitWithAwait ();
12766 public override Expression CreateExpressionTree (ResolveContext rc)
12768 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12772 protected override Expression DoResolve (ResolveContext rc)
12774 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12779 expr = Throw.ConvertType (rc, expr);
12781 eclass = ExprClass.Value;
12782 type = InternalType.ThrowExpr;
12786 public override void Emit (EmitContext ec)
12788 EmitStatement (ec);
12791 public override void EmitStatement (EmitContext ec)
12795 ec.Emit (OpCodes.Throw);
12798 public override void FlowAnalysis (FlowAnalysisContext fc)
12800 expr.FlowAnalysis (fc);
12803 public override Reachability MarkReachable (Reachability rc)
12805 return Reachability.CreateUnreachable ();