2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
721 if (ec.CurrentIterator != null) {
722 UnsafeInsideIteratorError (ec, loc);
723 } else if (!ec.IsUnsafe) {
724 UnsafeError (ec, loc);
727 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
728 if (Expr == null || Expr.eclass != ExprClass.Variable) {
729 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
733 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
737 IVariableReference vr = Expr as IVariableReference;
740 is_fixed = vr.IsFixed;
741 vr.SetHasAddressTaken ();
743 if (vr.IsHoisted && ec.CurrentIterator == null) {
744 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
747 IFixedExpression fe = Expr as IFixedExpression;
748 is_fixed = fe != null && fe.IsFixed;
751 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
752 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
755 type = PointerContainer.MakeType (ec.Module, Expr.Type);
756 eclass = ExprClass.Value;
760 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
762 expr = DoNumericPromotion (rc, Oper, expr);
763 TypeSpec expr_type = expr.Type;
764 foreach (TypeSpec t in predefined) {
772 // Perform user-operator overload resolution
774 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
776 CSharp.Operator.OpType op_type;
778 case Operator.LogicalNot:
779 op_type = CSharp.Operator.OpType.LogicalNot; break;
780 case Operator.OnesComplement:
781 op_type = CSharp.Operator.OpType.OnesComplement; break;
782 case Operator.UnaryNegation:
783 op_type = CSharp.Operator.OpType.UnaryNegation; break;
784 case Operator.UnaryPlus:
785 op_type = CSharp.Operator.OpType.UnaryPlus; break;
787 throw new InternalErrorException (Oper.ToString ());
790 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
794 Arguments args = new Arguments (1);
795 args.Add (new Argument (expr));
797 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
798 var oper = res.ResolveOperator (ec, ref args);
803 Expr = args [0].Expr;
804 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
808 // Unary user type overload resolution
810 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
812 Expression best_expr = ResolveUserOperator (ec, expr);
813 if (best_expr != null)
816 foreach (TypeSpec t in predefined) {
817 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
818 if (oper_expr == null)
821 if (oper_expr == ErrorExpression.Instance)
825 // decimal type is predefined but has user-operators
827 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
828 oper_expr = ResolveUserType (ec, oper_expr, predefined);
830 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
832 if (oper_expr == null)
835 if (best_expr == null) {
836 best_expr = oper_expr;
840 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
842 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
843 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
845 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
852 best_expr = oper_expr;
855 if (best_expr == null)
859 // HACK: Decimal user-operator is included in standard operators
861 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
865 type = best_expr.Type;
869 protected override void CloneTo (CloneContext clonectx, Expression t)
871 Unary target = (Unary) t;
873 target.Expr = Expr.Clone (clonectx);
876 public override object Accept (StructuralVisitor visitor)
878 return visitor.Visit (this);
884 // Unary operators are turned into Indirection expressions
885 // after semantic analysis (this is so we can take the address
886 // of an indirection).
888 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
890 LocalTemporary temporary;
893 public Indirection (Expression expr, Location l)
899 public Expression Expr {
905 public bool IsFixed {
909 public override Location StartLocation {
911 return expr.StartLocation;
915 protected override void CloneTo (CloneContext clonectx, Expression t)
917 Indirection target = (Indirection) t;
918 target.expr = expr.Clone (clonectx);
921 public override bool ContainsEmitWithAwait ()
923 throw new NotImplementedException ();
926 public override Expression CreateExpressionTree (ResolveContext ec)
928 Error_PointerInsideExpressionTree (ec);
932 public override void Emit (EmitContext ec)
937 ec.EmitLoadFromPtr (Type);
940 public void Emit (EmitContext ec, bool leave_copy)
944 ec.Emit (OpCodes.Dup);
945 temporary = new LocalTemporary (expr.Type);
946 temporary.Store (ec);
950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
952 prepared = isCompound;
957 ec.Emit (OpCodes.Dup);
961 ec.Emit (OpCodes.Dup);
962 temporary = new LocalTemporary (source.Type);
963 temporary.Store (ec);
966 ec.EmitStoreFromPtr (type);
968 if (temporary != null) {
970 temporary.Release (ec);
974 public void AddressOf (EmitContext ec, AddressOp Mode)
979 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
981 return DoResolve (ec);
984 protected override Expression DoResolve (ResolveContext ec)
986 expr = expr.Resolve (ec);
990 if (ec.CurrentIterator != null) {
991 UnsafeInsideIteratorError (ec, loc);
992 } else if (!ec.IsUnsafe) {
993 UnsafeError (ec, loc);
996 var pc = expr.Type as PointerContainer;
999 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1005 if (type.Kind == MemberKind.Void) {
1006 Error_VoidPointerOperation (ec);
1010 eclass = ExprClass.Variable;
1014 public override object Accept (StructuralVisitor visitor)
1016 return visitor.Visit (this);
1021 /// Unary Mutator expressions (pre and post ++ and --)
1025 /// UnaryMutator implements ++ and -- expressions. It derives from
1026 /// ExpressionStatement becuase the pre/post increment/decrement
1027 /// operators can be used in a statement context.
1029 /// FIXME: Idea, we could split this up in two classes, one simpler
1030 /// for the common case, and one with the extra fields for more complex
1031 /// classes (indexers require temporary access; overloaded require method)
1034 public class UnaryMutator : ExpressionStatement
1036 class DynamicPostMutator : Expression, IAssignMethod
1038 LocalTemporary temp;
1041 public DynamicPostMutator (Expression expr)
1044 this.type = expr.Type;
1045 this.loc = expr.Location;
1048 public override Expression CreateExpressionTree (ResolveContext ec)
1050 throw new NotImplementedException ("ET");
1053 protected override Expression DoResolve (ResolveContext rc)
1055 eclass = expr.eclass;
1059 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1061 expr.DoResolveLValue (ec, right_side);
1062 return DoResolve (ec);
1065 public override void Emit (EmitContext ec)
1070 public void Emit (EmitContext ec, bool leave_copy)
1072 throw new NotImplementedException ();
1076 // Emits target assignment using unmodified source value
1078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1081 // Allocate temporary variable to keep original value before it's modified
1083 temp = new LocalTemporary (type);
1087 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1098 public enum Mode : byte {
1105 PreDecrement = IsDecrement,
1106 PostIncrement = IsPost,
1107 PostDecrement = IsPost | IsDecrement
1111 bool is_expr, recurse;
1113 protected Expression expr;
1115 // Holds the real operation
1116 Expression operation;
1118 public UnaryMutator (Mode m, Expression e, Location loc)
1125 public Mode UnaryMutatorMode {
1131 public Expression Expr {
1137 public override Location StartLocation {
1139 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1143 public override bool ContainsEmitWithAwait ()
1145 return expr.ContainsEmitWithAwait ();
1148 public override Expression CreateExpressionTree (ResolveContext ec)
1150 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1153 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1156 // Predefined ++ and -- operators exist for the following types:
1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1159 return new TypeSpec[] {
1175 protected override Expression DoResolve (ResolveContext ec)
1177 expr = expr.Resolve (ec);
1179 if (expr == null || expr.Type == InternalType.ErrorType)
1182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 // Handle postfix unary operators using local
1185 // temporary variable
1187 if ((mode & Mode.IsPost) != 0)
1188 expr = new DynamicPostMutator (expr);
1190 Arguments args = new Arguments (1);
1191 args.Add (new Argument (expr));
1192 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1195 if (expr.Type.IsNullableType)
1196 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1198 return DoResolveOperation (ec);
1201 protected Expression DoResolveOperation (ResolveContext ec)
1203 eclass = ExprClass.Value;
1206 if (expr is RuntimeValueExpression) {
1209 // Use itself at the top of the stack
1210 operation = new EmptyExpression (type);
1214 // The operand of the prefix/postfix increment decrement operators
1215 // should be an expression that is classified as a variable,
1216 // a property access or an indexer access
1218 // TODO: Move to parser, expr is ATypeNameExpression
1219 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1220 expr = expr.ResolveLValue (ec, expr);
1222 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1226 // Step 1: Try to find a user operator, it has priority over predefined ones
1228 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1229 var methods = MemberCache.GetUserOperator (type, user_op, false);
1231 if (methods != null) {
1232 Arguments args = new Arguments (1);
1233 args.Add (new Argument (expr));
1235 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1236 var method = res.ResolveOperator (ec, ref args);
1240 args[0].Expr = operation;
1241 operation = new UserOperatorCall (method, args, null, loc);
1242 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1247 // Step 2: Try predefined types
1250 Expression source = null;
1251 bool primitive_type;
1254 // Predefined without user conversion first for speed-up
1256 // Predefined ++ and -- operators exist for the following types:
1257 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1259 switch (type.BuiltinType) {
1260 case BuiltinTypeSpec.Type.Byte:
1261 case BuiltinTypeSpec.Type.SByte:
1262 case BuiltinTypeSpec.Type.Short:
1263 case BuiltinTypeSpec.Type.UShort:
1264 case BuiltinTypeSpec.Type.Int:
1265 case BuiltinTypeSpec.Type.UInt:
1266 case BuiltinTypeSpec.Type.Long:
1267 case BuiltinTypeSpec.Type.ULong:
1268 case BuiltinTypeSpec.Type.Char:
1269 case BuiltinTypeSpec.Type.Float:
1270 case BuiltinTypeSpec.Type.Double:
1271 case BuiltinTypeSpec.Type.Decimal:
1273 primitive_type = true;
1276 primitive_type = false;
1278 // ++/-- on pointer variables of all types except void*
1279 if (type.IsPointer) {
1280 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1281 Error_VoidPointerOperation (ec);
1287 Expression best_source = null;
1288 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1289 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1291 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1295 if (best_source == null) {
1296 best_source = source;
1300 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1305 best_source = source;
1309 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1313 source = best_source;
1316 // ++/-- on enum types
1317 if (source == null && type.IsEnum)
1320 if (source == null) {
1321 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1328 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1329 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1330 operation = new Binary (op, source, one);
1331 operation = operation.Resolve (ec);
1332 if (operation == null)
1333 throw new NotImplementedException ("should not be reached");
1335 if (operation.Type != type) {
1337 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1339 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1345 void EmitCode (EmitContext ec, bool is_expr)
1348 this.is_expr = is_expr;
1349 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1352 public override void Emit (EmitContext ec)
1355 // We use recurse to allow ourselfs to be the source
1356 // of an assignment. This little hack prevents us from
1357 // having to allocate another expression
1360 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1368 EmitCode (ec, true);
1371 protected virtual void EmitOperation (EmitContext ec)
1373 operation.Emit (ec);
1376 public override void EmitStatement (EmitContext ec)
1378 EmitCode (ec, false);
1381 public override void FlowAnalysis (FlowAnalysisContext fc)
1383 expr.FlowAnalysis (fc);
1387 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1389 string GetOperatorExpressionTypeName ()
1391 return IsDecrement ? "Decrement" : "Increment";
1395 get { return (mode & Mode.IsDecrement) != 0; }
1399 public override SLE.Expression MakeExpression (BuilderContext ctx)
1401 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1402 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1403 return SLE.Expression.Assign (target, source);
1406 public static string OperName (Mode oper)
1408 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1411 protected override void CloneTo (CloneContext clonectx, Expression t)
1413 UnaryMutator target = (UnaryMutator) t;
1415 target.expr = expr.Clone (clonectx);
1418 public override object Accept (StructuralVisitor visitor)
1420 return visitor.Visit (this);
1426 // Base class for the `is' and `as' operators
1428 public abstract class Probe : Expression
1430 public Expression ProbeType;
1431 protected Expression expr;
1432 protected TypeSpec probe_type_expr;
1434 protected Probe (Expression expr, Expression probe_type, Location l)
1436 ProbeType = probe_type;
1441 public Expression Expr {
1447 public override bool ContainsEmitWithAwait ()
1449 return expr.ContainsEmitWithAwait ();
1452 protected Expression ResolveCommon (ResolveContext rc)
1454 expr = expr.Resolve (rc);
1458 ResolveProbeType (rc);
1459 if (probe_type_expr == null)
1462 if (probe_type_expr.IsStatic) {
1463 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1464 probe_type_expr.GetSignatureForError ());
1468 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1469 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1474 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1475 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1483 protected virtual void ResolveProbeType (ResolveContext rc)
1485 probe_type_expr = ProbeType.ResolveAsType (rc);
1488 public override void EmitSideEffect (EmitContext ec)
1490 expr.EmitSideEffect (ec);
1493 public override void EmitPrepare (EmitContext ec)
1495 expr.EmitPrepare (ec);
1498 public override void FlowAnalysis (FlowAnalysisContext fc)
1500 expr.FlowAnalysis (fc);
1503 public override bool HasConditionalAccess ()
1505 return expr.HasConditionalAccess ();
1508 protected abstract string OperatorName { get; }
1510 protected override void CloneTo (CloneContext clonectx, Expression t)
1512 Probe target = (Probe) t;
1514 target.expr = expr.Clone (clonectx);
1515 target.ProbeType = ProbeType.Clone (clonectx);
1521 /// Implementation of the `is' operator.
1523 public class Is : Probe
1525 Nullable.Unwrap expr_unwrap;
1526 MethodSpec number_mg;
1527 Arguments number_args;
1529 public Is (Expression expr, Expression probe_type, Location l)
1530 : base (expr, probe_type, l)
1534 protected override string OperatorName {
1535 get { return "is"; }
1538 public LocalVariable Variable { get; set; }
1540 public override Expression CreateExpressionTree (ResolveContext ec)
1542 if (Variable != null)
1543 ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
1545 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1546 expr.CreateExpressionTree (ec),
1547 new TypeOf (probe_type_expr, loc));
1549 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1552 Expression CreateConstantResult (ResolveContext rc, bool result)
1555 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1556 probe_type_expr.GetSignatureForError ());
1558 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1559 probe_type_expr.GetSignatureForError ());
1561 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1562 return expr.IsSideEffectFree ?
1563 ReducedExpression.Create (c, this) :
1564 new SideEffectConstant (c, this, loc);
1567 public override void Emit (EmitContext ec)
1569 if (probe_type_expr == null) {
1570 if (ProbeType is WildcardPattern) {
1571 expr.EmitSideEffect (ec);
1572 ProbeType.Emit (ec);
1574 EmitPatternMatch (ec);
1581 if (expr_unwrap == null) {
1583 ec.Emit (OpCodes.Cgt_Un);
1587 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1589 if (probe_type_expr == null) {
1590 EmitPatternMatch (ec);
1595 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1598 public override void EmitPrepare (EmitContext ec)
1600 base.EmitPrepare (ec);
1602 if (Variable != null)
1603 Variable.CreateBuilder (ec);
1606 void EmitPatternMatch (EmitContext ec)
1608 var no_match = ec.DefineLabel ();
1609 var end = ec.DefineLabel ();
1611 if (expr_unwrap != null) {
1612 expr_unwrap.EmitCheck (ec);
1614 if (ProbeType.IsNull) {
1616 ec.Emit (OpCodes.Ceq);
1620 ec.Emit (OpCodes.Brfalse_S, no_match);
1621 expr_unwrap.Emit (ec);
1622 ProbeType.Emit (ec);
1623 ec.Emit (OpCodes.Ceq);
1624 ec.Emit (OpCodes.Br_S, end);
1625 ec.MarkLabel (no_match);
1631 if (number_args != null && number_args.Count == 3) {
1632 var ce = new CallEmitter ();
1633 ce.Emit (ec, number_mg, number_args, loc);
1637 var probe_type = ProbeType.Type;
1640 ec.Emit (OpCodes.Isinst, probe_type);
1641 ec.Emit (OpCodes.Dup);
1642 ec.Emit (OpCodes.Brfalse, no_match);
1644 bool complex_pattern = ProbeType is ComplexPatternExpression;
1645 Label prev = ec.RecursivePatternLabel;
1646 if (complex_pattern)
1647 ec.RecursivePatternLabel = ec.DefineLabel ();
1649 if (number_mg != null) {
1650 var ce = new CallEmitter ();
1651 ce.Emit (ec, number_mg, number_args, loc);
1653 if (TypeSpec.IsValueType (probe_type))
1654 ec.Emit (OpCodes.Unbox_Any, probe_type);
1656 ProbeType.Emit (ec);
1657 if (complex_pattern) {
1660 ec.Emit (OpCodes.Ceq);
1663 ec.Emit (OpCodes.Br_S, end);
1664 ec.MarkLabel (no_match);
1666 ec.Emit (OpCodes.Pop);
1668 if (complex_pattern)
1669 ec.MarkLabel (ec.RecursivePatternLabel);
1671 ec.RecursivePatternLabel = prev;
1677 void EmitLoad (EmitContext ec)
1679 if (expr_unwrap != null) {
1680 expr_unwrap.EmitCheck (ec);
1682 if (Variable == null)
1685 ec.Emit (OpCodes.Dup);
1686 var no_value_label = ec.DefineLabel ();
1687 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1689 if (Variable.HoistedVariant != null)
1692 expr_unwrap.Emit (ec);
1694 if (Variable.HoistedVariant != null) {
1695 Variable.HoistedVariant.EmitAssignFromStack (ec);
1698 // It's ok to have variable builder created out of order. It simplifies emit
1699 // of statements like while (condition) { }
1701 if (!Variable.Created)
1702 Variable.CreateBuilder (ec);
1704 Variable.EmitAssign (ec);
1707 ec.MarkLabel (no_value_label);
1713 bool vtype_variable = Variable != null && (probe_type_expr.IsGenericParameter || TypeSpec.IsValueType (ProbeType.Type));
1714 LocalBuilder expr_copy = null;
1716 if (vtype_variable && !ExpressionAnalyzer.IsInexpensiveLoad (expr)) {
1717 expr_copy = ec.GetTemporaryLocal (expr.Type);
1718 ec.Emit (OpCodes.Stloc, expr_copy);
1719 ec.Emit (OpCodes.Ldloc, expr_copy);
1720 } else if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type)) {
1722 // Only to make verifier happy
1724 ec.Emit (OpCodes.Box, expr.Type);
1727 ec.Emit (OpCodes.Isinst, probe_type_expr);
1729 if (Variable != null) {
1730 ec.Emit (OpCodes.Dup);
1732 var nonmatching_label = ec.DefineLabel ();
1733 ec.Emit (OpCodes.Brfalse_S, nonmatching_label);
1735 if (vtype_variable) {
1736 if (expr_copy != null) {
1737 ec.Emit (OpCodes.Ldloc, expr_copy);
1738 ec.FreeTemporaryLocal (expr_copy, expr.Type);
1743 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1745 // Already on the stack
1748 if (Variable.HoistedVariant != null) {
1749 var temp = new LocalTemporary (ProbeType.Type);
1751 Variable.HoistedVariant.EmitAssign (ec, temp, false, false);
1754 if (!vtype_variable)
1755 Variable.HoistedVariant.Emit (ec);
1758 // It's ok to have variable builder created out of order. It simplifies emit
1759 // of statements like while (condition) { }
1761 if (!Variable.Created)
1762 Variable.CreateBuilder (ec);
1764 Variable.EmitAssign (ec);
1766 if (!vtype_variable)
1770 ec.MarkLabel (nonmatching_label);
1774 protected override Expression DoResolve (ResolveContext rc)
1776 if (ResolveCommon (rc) == null)
1779 type = rc.BuiltinTypes.Bool;
1780 eclass = ExprClass.Value;
1782 if (probe_type_expr == null)
1783 return ResolveMatchingExpression (rc);
1785 var res = ResolveResultExpression (rc);
1786 if (Variable != null) {
1787 if (res is Constant)
1788 throw new NotImplementedException ("constant in type pattern matching");
1790 Variable.Type = probe_type_expr;
1791 var bc = rc as BlockContext;
1793 Variable.PrepareAssignmentAnalysis (bc);
1799 public override void FlowAnalysis (FlowAnalysisContext fc)
1801 base.FlowAnalysis (fc);
1803 if (Variable != null)
1804 fc.SetVariableAssigned (Variable.VariableInfo, true);
1807 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
1809 if (Variable == null) {
1810 base.FlowAnalysisConditional (fc);
1814 expr.FlowAnalysis (fc);
1816 fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
1817 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1819 fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
1822 protected override void ResolveProbeType (ResolveContext rc)
1824 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1825 if (ProbeType is PatternExpression) {
1826 ProbeType.Resolve (rc);
1831 // Have to use session recording because we don't have reliable type probing
1832 // mechanism (similar issue as in attributes resolving)
1834 // TODO: This is still wrong because ResolveAsType can be destructive
1836 var type_printer = new SessionReportPrinter ();
1837 var prev_recorder = rc.Report.SetPrinter (type_printer);
1839 probe_type_expr = ProbeType.ResolveAsType (rc);
1840 type_printer.EndSession ();
1842 if (probe_type_expr != null) {
1843 type_printer.Merge (rc.Report.Printer);
1844 rc.Report.SetPrinter (prev_recorder);
1848 var vexpr = ProbeType as VarExpr;
1849 if (vexpr != null && vexpr.InferType (rc, expr)) {
1850 probe_type_expr = vexpr.Type;
1851 rc.Report.SetPrinter (prev_recorder);
1855 var expr_printer = new SessionReportPrinter ();
1856 rc.Report.SetPrinter (expr_printer);
1857 ProbeType = ProbeType.Resolve (rc);
1858 expr_printer.EndSession ();
1860 if (ProbeType != null) {
1861 expr_printer.Merge (rc.Report.Printer);
1863 type_printer.Merge (rc.Report.Printer);
1866 rc.Report.SetPrinter (prev_recorder);
1870 base.ResolveProbeType (rc);
1873 Expression ResolveMatchingExpression (ResolveContext rc)
1875 var mc = ProbeType as Constant;
1877 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1878 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1883 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1885 var c = Expr as Constant;
1887 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1892 if (Expr.Type.IsNullableType) {
1893 expr_unwrap = new Nullable.Unwrap (Expr);
1894 expr_unwrap.Resolve (rc);
1895 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1896 } else if (ProbeType.Type == Expr.Type) {
1897 // TODO: Better error handling
1898 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1899 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1900 var helper = rc.Module.CreatePatterMatchingHelper ();
1901 number_mg = helper.NumberMatcher.Spec;
1904 // There are actually 3 arguments but the first one is already on the stack
1906 number_args = new Arguments (3);
1907 if (!ProbeType.Type.IsEnum)
1908 number_args.Add (new Argument (Expr));
1910 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1911 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1917 if (ProbeType is PatternExpression) {
1918 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1919 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1925 // TODO: Better error message
1926 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1930 Expression ResolveResultExpression (ResolveContext ec)
1932 if (Variable != null) {
1933 if (expr is NullLiteral) {
1934 ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
1938 CheckExpressionVariable (ec);
1941 TypeSpec d = expr.Type;
1942 bool d_is_nullable = false;
1945 // If E is a method group or the null literal, or if the type of E is a reference
1946 // type or a nullable type and the value of E is null, the result is false
1949 return CreateConstantResult (ec, false);
1951 if (d.IsNullableType) {
1952 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1953 if (!ut.IsGenericParameter) {
1955 d_is_nullable = true;
1959 TypeSpec t = probe_type_expr;
1960 bool t_is_nullable = false;
1961 if (t.IsNullableType) {
1962 if (Variable != null) {
1963 ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
1964 t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
1967 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1968 if (!ut.IsGenericParameter) {
1970 t_is_nullable = true;
1977 // D and T are the same value types but D can be null
1979 if (d_is_nullable && !t_is_nullable) {
1980 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1985 // The result is true if D and T are the same value types
1987 return CreateConstantResult (ec, true);
1990 var tp = d as TypeParameterSpec;
1992 return ResolveGenericParameter (ec, t, tp);
1995 // An unboxing conversion exists
1997 if (Convert.ExplicitReferenceConversionExists (d, t))
2001 // open generic type
2003 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
2006 var tps = t as TypeParameterSpec;
2008 return ResolveGenericParameter (ec, d, tps);
2010 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2011 if (Variable != null) {
2012 ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
2014 ec.Report.Warning (1981, 3, loc,
2015 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
2016 OperatorName, t.GetSignatureForError ());
2020 if (TypeManager.IsGenericParameter (d))
2021 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
2023 if (TypeSpec.IsValueType (d)) {
2024 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
2025 if (d_is_nullable && !t_is_nullable) {
2026 expr_unwrap = Nullable.Unwrap.Create (expr, false);
2030 return CreateConstantResult (ec, true);
2033 if (Convert.ImplicitReferenceConversionExists (d, t)) {
2034 var c = expr as Constant;
2036 return CreateConstantResult (ec, !c.IsNull);
2039 // Do not optimize for imported type or dynamic type
2041 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
2042 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
2046 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
2050 // Turn is check into simple null check for implicitly convertible reference types
2052 return ReducedExpression.Create (
2053 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
2057 if (Convert.ExplicitReferenceConversionExists (d, t))
2061 // open generic type
2063 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
2068 return CreateConstantResult (ec, false);
2071 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
2073 if (t.IsReferenceType) {
2075 return CreateConstantResult (ec, false);
2078 if (expr.Type.IsGenericParameter) {
2079 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2080 return CreateConstantResult (ec, true);
2082 expr = new BoxedCast (expr, d);
2088 public override object Accept (StructuralVisitor visitor)
2090 return visitor.Visit (this);
2094 class WildcardPattern : PatternExpression
2096 public WildcardPattern (Location loc)
2101 protected override Expression DoResolve (ResolveContext rc)
2103 eclass = ExprClass.Value;
2104 type = rc.BuiltinTypes.Object;
2108 public override void Emit (EmitContext ec)
2114 class RecursivePattern : ComplexPatternExpression
2116 MethodGroupExpr operator_mg;
2117 Arguments operator_args;
2119 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2120 : base (typeExpresion, loc)
2122 Arguments = arguments;
2125 public Arguments Arguments { get; private set; }
2127 protected override Expression DoResolve (ResolveContext rc)
2129 type = TypeExpression.ResolveAsType (rc);
2133 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2134 if (operators == null) {
2135 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2139 var ops = FindMatchingOverloads (operators);
2141 // TODO: better error message
2142 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2147 Arguments.Resolve (rc, out dynamic_args);
2149 throw new NotImplementedException ("dynamic argument");
2151 var op = FindBestOverload (rc, ops);
2153 // TODO: better error message
2154 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2158 var op_types = op.Parameters.Types;
2159 operator_args = new Arguments (op_types.Length);
2160 operator_args.Add (new Argument (new EmptyExpression (type)));
2162 for (int i = 0; i < Arguments.Count; ++i) {
2163 // TODO: Needs releasing optimization
2164 var lt = new LocalTemporary (op_types [i + 1]);
2165 operator_args.Add (new Argument (lt, Argument.AType.Out));
2167 if (comparisons == null)
2168 comparisons = new Expression[Arguments.Count];
2173 var arg = Arguments [i];
2174 var named = arg as NamedArgument;
2175 if (named != null) {
2176 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2177 expr = Arguments [arg_comp_index].Expr;
2183 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2186 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2188 eclass = ExprClass.Value;
2192 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2194 int arg_count = Arguments.Count + 1;
2195 List<MethodSpec> best = null;
2196 foreach (MethodSpec method in members) {
2197 var pm = method.Parameters;
2198 if (pm.Count != arg_count)
2201 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2203 for (int ii = 1; ii < pm.Count; ++ii) {
2204 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2214 best = new List<MethodSpec> ();
2222 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2224 for (int ii = 0; ii < Arguments.Count; ++ii) {
2225 var arg = Arguments [ii];
2226 var expr = arg.Expr;
2227 if (expr is WildcardPattern)
2230 var na = arg as NamedArgument;
2231 for (int i = 0; i < methods.Count; ++i) {
2232 var pd = methods [i].Parameters;
2236 index = pd.GetParameterIndexByName (na.Name);
2238 methods.RemoveAt (i--);
2245 var m = pd.Types [index];
2246 if (!Convert.ImplicitConversionExists (rc, expr, m))
2247 methods.RemoveAt (i--);
2251 if (methods.Count != 1)
2257 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2259 operator_mg.EmitCall (ec, operator_args, false);
2260 ec.Emit (OpCodes.Brfalse, target);
2262 base.EmitBranchable (ec, target, on_true);
2265 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2267 if (expr is WildcardPattern)
2268 return new EmptyExpression (expr.Type);
2270 var recursive = expr as RecursivePattern;
2271 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2275 if (recursive != null) {
2276 recursive.SetParentInstance (lt);
2280 // TODO: Better error handling
2281 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2284 public void SetParentInstance (Expression instance)
2286 operator_args [0] = new Argument (instance);
2290 class PropertyPattern : ComplexPatternExpression
2292 LocalTemporary instance;
2294 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2295 : base (typeExpresion, loc)
2300 public List<PropertyPatternMember> Members { get; private set; }
2302 protected override Expression DoResolve (ResolveContext rc)
2304 type = TypeExpression.ResolveAsType (rc);
2308 comparisons = new Expression[Members.Count];
2310 // TODO: optimize when source is VariableReference, it'd save dup+pop
2311 instance = new LocalTemporary (type);
2313 for (int i = 0; i < Members.Count; i++) {
2314 var lookup = Members [i];
2316 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2317 if (member == null) {
2318 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2319 if (member != null) {
2320 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2325 if (member == null) {
2326 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2330 var pe = member as PropertyExpr;
2331 if (pe == null || member is FieldExpr) {
2332 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2336 // TODO: Obsolete checks
2337 // TODO: check accessibility
2338 if (pe != null && !pe.PropertyInfo.HasGet) {
2339 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2343 var expr = lookup.Expr.Resolve (rc);
2347 var me = (MemberExpr)member;
2348 me.InstanceExpression = instance;
2350 comparisons [i] = ResolveComparison (rc, expr, me);
2353 eclass = ExprClass.Value;
2357 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2359 if (expr is WildcardPattern)
2360 return new EmptyExpression (expr.Type);
2362 return new Is (instance, expr, expr.Location).Resolve (rc);
2365 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2367 instance.Store (ec);
2369 base.EmitBranchable (ec, target, on_true);
2373 class PropertyPatternMember
2375 public PropertyPatternMember (string name, Expression expr, Location loc)
2382 public string Name { get; private set; }
2383 public Expression Expr { get; private set; }
2384 public Location Location { get; private set; }
2387 abstract class PatternExpression : Expression
2389 protected PatternExpression (Location loc)
2394 public override Expression CreateExpressionTree (ResolveContext ec)
2396 throw new NotImplementedException ();
2400 abstract class ComplexPatternExpression : PatternExpression
2402 protected Expression[] comparisons;
2404 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2407 TypeExpression = typeExpresion;
2410 public ATypeNameExpression TypeExpression { get; private set; }
2412 public override void Emit (EmitContext ec)
2414 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2417 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2419 if (comparisons != null) {
2420 foreach (var comp in comparisons) {
2421 comp.EmitBranchable (ec, target, false);
2428 /// Implementation of the `as' operator.
2430 public class As : Probe {
2432 public As (Expression expr, Expression probe_type, Location l)
2433 : base (expr, probe_type, l)
2437 protected override string OperatorName {
2438 get { return "as"; }
2441 public override Expression CreateExpressionTree (ResolveContext ec)
2443 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2444 expr.CreateExpressionTree (ec),
2445 new TypeOf (probe_type_expr, loc));
2447 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2450 public override void Emit (EmitContext ec)
2454 ec.Emit (OpCodes.Isinst, type);
2456 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2457 ec.Emit (OpCodes.Unbox_Any, type);
2460 protected override Expression DoResolve (ResolveContext ec)
2462 if (ResolveCommon (ec) == null)
2465 type = probe_type_expr;
2466 eclass = ExprClass.Value;
2467 TypeSpec etype = expr.Type;
2469 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) {
2470 ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type");
2471 type = InternalType.ErrorType;
2476 type = InternalType.ErrorType;
2480 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2481 if (TypeManager.IsGenericParameter (type)) {
2482 ec.Report.Error (413, loc,
2483 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2484 probe_type_expr.GetSignatureForError ());
2486 ec.Report.Error (77, loc,
2487 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2488 type.GetSignatureForError ());
2493 if (expr.IsNull && type.IsNullableType) {
2494 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2497 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2498 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2502 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2504 e = EmptyCast.Create (e, type);
2505 return ReducedExpression.Create (e, this).Resolve (ec);
2508 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2509 if (TypeManager.IsGenericParameter (etype))
2510 expr = new BoxedCast (expr, etype);
2515 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2516 expr = new BoxedCast (expr, etype);
2520 if (etype != InternalType.ErrorType) {
2521 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2522 etype.GetSignatureForError (), type.GetSignatureForError ());
2528 public override object Accept (StructuralVisitor visitor)
2530 return visitor.Visit (this);
2535 // This represents a typecast in the source language.
2537 public class Cast : ShimExpression {
2538 Expression target_type;
2540 public Cast (Expression cast_type, Expression expr, Location loc)
2543 this.target_type = cast_type;
2547 public Expression TargetType {
2548 get { return target_type; }
2551 protected override Expression DoResolve (ResolveContext ec)
2553 expr = expr.Resolve (ec);
2557 type = target_type.ResolveAsType (ec);
2561 if (type.IsStatic) {
2562 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2566 if (type.IsPointer) {
2567 if (ec.CurrentIterator != null) {
2568 UnsafeInsideIteratorError (ec, loc);
2569 } else if (!ec.IsUnsafe) {
2570 UnsafeError (ec, loc);
2574 eclass = ExprClass.Value;
2576 Constant c = expr as Constant;
2578 c = c.Reduce (ec, type);
2583 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2585 return EmptyCast.Create (res, type);
2590 protected override void CloneTo (CloneContext clonectx, Expression t)
2592 Cast target = (Cast) t;
2594 target.target_type = target_type.Clone (clonectx);
2595 target.expr = expr.Clone (clonectx);
2598 public override object Accept (StructuralVisitor visitor)
2600 return visitor.Visit (this);
2604 public class ImplicitCast : ShimExpression
2608 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2611 this.loc = expr.Location;
2613 this.arrayAccess = arrayAccess;
2616 protected override Expression DoResolve (ResolveContext ec)
2618 expr = expr.Resolve (ec);
2623 expr = ConvertExpressionToArrayIndex (ec, expr);
2625 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2631 public class DeclarationExpression : Expression, IMemoryLocation
2633 LocalVariableReference lvr;
2635 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2637 VariableType = variableType;
2638 Variable = variable;
2639 this.loc = variable.Location;
2642 public LocalVariable Variable { get; set; }
2643 public Expression Initializer { get; set; }
2644 public FullNamedExpression VariableType { get; set; }
2646 public void AddressOf (EmitContext ec, AddressOp mode)
2648 if (!Variable.Created)
2649 Variable.CreateBuilder (ec);
2651 if (Initializer != null) {
2652 lvr.EmitAssign (ec, Initializer, false, false);
2655 lvr.AddressOf (ec, mode);
2658 protected override void CloneTo (CloneContext clonectx, Expression t)
2660 var target = (DeclarationExpression) t;
2662 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2664 if (Initializer != null)
2665 target.Initializer = Initializer.Clone (clonectx);
2668 public override Expression CreateExpressionTree (ResolveContext rc)
2670 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2674 bool DoResolveCommon (ResolveContext rc)
2676 CheckExpressionVariable (rc);
2678 var var_expr = VariableType as VarExpr;
2679 if (var_expr != null) {
2680 type = InternalType.VarOutType;
2682 type = VariableType.ResolveAsType (rc);
2687 if (Initializer != null) {
2688 Initializer = Initializer.Resolve (rc);
2690 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2691 type = var_expr.Type;
2695 Variable.Type = type;
2696 lvr = new LocalVariableReference (Variable, loc);
2698 eclass = ExprClass.Variable;
2702 protected override Expression DoResolve (ResolveContext rc)
2704 if (DoResolveCommon (rc))
2710 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2712 if (lvr == null && DoResolveCommon (rc))
2713 lvr.ResolveLValue (rc, right_side);
2718 public override void Emit (EmitContext ec)
2720 throw new NotImplementedException ();
2723 public override void EmitPrepare (EmitContext ec)
2725 Variable.CreateBuilder (ec);
2730 // C# 2.0 Default value expression
2732 public class DefaultValueExpression : Expression
2736 public DefaultValueExpression (Expression expr, Location loc)
2742 public Expression Expr {
2748 public override bool IsSideEffectFree {
2754 public override bool ContainsEmitWithAwait ()
2759 public override Expression CreateExpressionTree (ResolveContext ec)
2761 Arguments args = new Arguments (2);
2762 args.Add (new Argument (this));
2763 args.Add (new Argument (new TypeOf (type, loc)));
2764 return CreateExpressionFactoryCall (ec, "Constant", args);
2767 protected override Expression DoResolve (ResolveContext ec)
2769 type = expr.ResolveAsType (ec);
2773 if (type.IsStatic) {
2774 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2778 return new NullLiteral (Location).ConvertImplicitly (type);
2780 if (TypeSpec.IsReferenceType (type))
2781 return new NullConstant (type, loc);
2783 Constant c = New.Constantify (type, expr.Location);
2787 eclass = ExprClass.Variable;
2791 public override void Emit (EmitContext ec)
2793 LocalTemporary temp_storage = new LocalTemporary(type);
2795 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2796 ec.Emit(OpCodes.Initobj, type);
2797 temp_storage.Emit(ec);
2798 temp_storage.Release (ec);
2802 public override SLE.Expression MakeExpression (BuilderContext ctx)
2804 return SLE.Expression.Default (type.GetMetaInfo ());
2808 protected override void CloneTo (CloneContext clonectx, Expression t)
2810 DefaultValueExpression target = (DefaultValueExpression) t;
2812 target.expr = expr.Clone (clonectx);
2815 public override object Accept (StructuralVisitor visitor)
2817 return visitor.Visit (this);
2822 /// Binary operators
2824 public class Binary : Expression, IDynamicBinder
2826 public class PredefinedOperator
2828 protected readonly TypeSpec left;
2829 protected readonly TypeSpec right;
2830 protected readonly TypeSpec left_unwrap;
2831 protected readonly TypeSpec right_unwrap;
2832 public readonly Operator OperatorsMask;
2833 public TypeSpec ReturnType;
2835 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2836 : this (ltype, rtype, op_mask, ltype)
2840 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2841 : this (type, type, op_mask, return_type)
2845 public PredefinedOperator (TypeSpec type, Operator op_mask)
2846 : this (type, type, op_mask, type)
2850 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2852 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2853 throw new InternalErrorException ("Only masked values can be used");
2855 if ((op_mask & Operator.NullableMask) != 0) {
2856 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2857 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2859 left_unwrap = ltype;
2860 right_unwrap = rtype;
2865 this.OperatorsMask = op_mask;
2866 this.ReturnType = return_type;
2869 public bool IsLifted {
2871 return (OperatorsMask & Operator.NullableMask) != 0;
2875 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2879 var left_expr = b.left;
2880 var right_expr = b.right;
2882 b.type = ReturnType;
2885 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2886 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2887 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2890 if (right_expr.IsNull) {
2891 if ((b.oper & Operator.EqualityMask) != 0) {
2892 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2893 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2894 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2895 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2896 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2898 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2899 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2901 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2902 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2904 return b.CreateLiftedValueTypeResult (rc, left);
2906 } else if (left_expr.IsNull) {
2907 if ((b.oper & Operator.EqualityMask) != 0) {
2908 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2909 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2910 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2911 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2912 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2914 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2915 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2917 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2918 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2920 return b.CreateLiftedValueTypeResult (rc, right);
2926 // A user operators does not support multiple user conversions, but decimal type
2927 // is considered to be predefined type therefore we apply predefined operators rules
2928 // and then look for decimal user-operator implementation
2930 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2931 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2932 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2934 return b.ResolveUserOperator (rc, b.left, b.right);
2937 c = right_expr as Constant;
2939 if (c.IsDefaultValue) {
2943 // (expr + 0) to expr
2944 // (expr - 0) to expr
2945 // (bool? | false) to bool?
2947 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2948 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2949 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2950 return ReducedExpression.Create (b.left, b).Resolve (rc);
2954 // Optimizes (value &/&& 0) to 0
2956 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2957 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2958 return ReducedExpression.Create (side_effect, b);
2962 // Optimizes (bool? & true) to bool?
2964 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2965 return ReducedExpression.Create (b.left, b).Resolve (rc);
2969 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2970 return ReducedExpression.Create (b.left, b).Resolve (rc);
2972 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2973 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2977 c = b.left as Constant;
2979 if (c.IsDefaultValue) {
2983 // (0 + expr) to expr
2984 // (false | bool?) to bool?
2986 if (b.oper == Operator.Addition ||
2987 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2988 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2989 return ReducedExpression.Create (b.right, b).Resolve (rc);
2993 // Optimizes (false && expr) to false
2995 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2996 // No rhs side-effects
2997 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2998 return ReducedExpression.Create (c, b);
3002 // Optimizes (0 & value) to 0
3004 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
3005 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
3006 return ReducedExpression.Create (side_effect, b);
3010 // Optimizes (true & bool?) to bool?
3012 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
3013 return ReducedExpression.Create (b.right, b).Resolve (rc);
3017 // Optimizes (true || expr) to true
3019 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3020 // No rhs side-effects
3021 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
3022 return ReducedExpression.Create (c, b);
3026 if (b.oper == Operator.Multiply && c.IsOneInteger)
3027 return ReducedExpression.Create (b.right, b).Resolve (rc);
3031 var lifted = new Nullable.LiftedBinaryOperator (b);
3033 TypeSpec ltype, rtype;
3034 if (b.left.Type.IsNullableType) {
3035 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
3036 ltype = left_unwrap;
3041 if (b.right.Type.IsNullableType) {
3042 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
3043 rtype = right_unwrap;
3048 lifted.Left = b.left.IsNull ?
3049 Nullable.LiftedNull.Create (ltype, b.left.Location) :
3050 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
3052 lifted.Right = b.right.IsNull ?
3053 Nullable.LiftedNull.Create (rtype, b.right.Location) :
3054 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
3056 return lifted.Resolve (rc);
3059 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3060 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3065 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3068 // We are dealing with primitive types only
3070 return left == ltype && ltype == rtype;
3073 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3076 if (left == lexpr.Type && right == rexpr.Type)
3079 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3080 Convert.ImplicitConversionExists (ec, rexpr, right);
3083 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3085 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3086 return best_operator;
3088 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3092 if (left != null && best_operator.left != null) {
3093 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3097 // When second argument is same as the first one, the result is same
3099 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3100 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3103 if (result == 0 || result > 2)
3106 return result == 1 ? best_operator : this;
3110 sealed class PredefinedStringOperator : PredefinedOperator
3112 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3113 : base (type, type, op_mask, retType)
3117 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3118 : base (ltype, rtype, op_mask, retType)
3122 public override Expression ConvertResult (ResolveContext ec, Binary b)
3125 // Use original expression for nullable arguments
3127 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3129 b.left = unwrap.Original;
3131 unwrap = b.right as Nullable.Unwrap;
3133 b.right = unwrap.Original;
3135 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3136 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3139 // Start a new concat expression using converted expression
3141 return StringConcat.Create (ec, b.left, b.right, b.loc);
3145 sealed class PredefinedEqualityOperator : PredefinedOperator
3147 MethodSpec equal_method, inequal_method;
3149 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3150 : base (arg, arg, Operator.EqualityMask, retType)
3154 public override Expression ConvertResult (ResolveContext ec, Binary b)
3156 b.type = ReturnType;
3158 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3159 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3161 Arguments args = new Arguments (2);
3162 args.Add (new Argument (b.left));
3163 args.Add (new Argument (b.right));
3166 if (b.oper == Operator.Equality) {
3167 if (equal_method == null) {
3168 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3169 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3170 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3171 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3173 throw new NotImplementedException (left.GetSignatureForError ());
3176 method = equal_method;
3178 if (inequal_method == null) {
3179 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3180 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3181 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3182 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3184 throw new NotImplementedException (left.GetSignatureForError ());
3187 method = inequal_method;
3190 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3194 class PredefinedPointerOperator : PredefinedOperator
3196 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3197 : base (ltype, rtype, op_mask)
3201 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3202 : base (ltype, rtype, op_mask, retType)
3206 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3207 : base (type, op_mask, return_type)
3211 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3214 if (!lexpr.Type.IsPointer)
3217 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3221 if (right == null) {
3222 if (!rexpr.Type.IsPointer)
3225 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3232 public override Expression ConvertResult (ResolveContext ec, Binary b)
3235 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3236 } else if (right != null) {
3237 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3240 TypeSpec r_type = ReturnType;
3241 Expression left_arg, right_arg;
3242 if (r_type == null) {
3245 right_arg = b.right;
3246 r_type = b.left.Type;
3250 r_type = b.right.Type;
3254 right_arg = b.right;
3257 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3262 public enum Operator {
3263 Multiply = 0 | ArithmeticMask,
3264 Division = 1 | ArithmeticMask,
3265 Modulus = 2 | ArithmeticMask,
3266 Addition = 3 | ArithmeticMask | AdditionMask,
3267 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3269 LeftShift = 5 | ShiftMask,
3270 RightShift = 6 | ShiftMask,
3272 LessThan = 7 | ComparisonMask | RelationalMask,
3273 GreaterThan = 8 | ComparisonMask | RelationalMask,
3274 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3275 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3276 Equality = 11 | ComparisonMask | EqualityMask,
3277 Inequality = 12 | ComparisonMask | EqualityMask,
3279 BitwiseAnd = 13 | BitwiseMask,
3280 ExclusiveOr = 14 | BitwiseMask,
3281 BitwiseOr = 15 | BitwiseMask,
3283 LogicalAnd = 16 | LogicalMask,
3284 LogicalOr = 17 | LogicalMask,
3289 ValuesOnlyMask = ArithmeticMask - 1,
3290 ArithmeticMask = 1 << 5,
3292 ComparisonMask = 1 << 7,
3293 EqualityMask = 1 << 8,
3294 BitwiseMask = 1 << 9,
3295 LogicalMask = 1 << 10,
3296 AdditionMask = 1 << 11,
3297 SubtractionMask = 1 << 12,
3298 RelationalMask = 1 << 13,
3300 DecomposedMask = 1 << 19,
3301 NullableMask = 1 << 20
3305 public enum State : byte
3309 UserOperatorsExcluded = 1 << 2
3312 readonly Operator oper;
3313 Expression left, right;
3315 ConvCast.Mode enum_conversion;
3317 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3318 : this (oper, left, right, State.Compound)
3322 public Binary (Operator oper, Expression left, Expression right, State state)
3323 : this (oper, left, right)
3328 public Binary (Operator oper, Expression left, Expression right)
3329 : this (oper, left, right, left.Location)
3333 public Binary (Operator oper, Expression left, Expression right, Location loc)
3343 public bool IsCompound {
3345 return (state & State.Compound) != 0;
3349 public Operator Oper {
3355 public Expression Left {
3361 public Expression Right {
3367 public override Location StartLocation {
3369 return left.StartLocation;
3376 /// Returns a stringified representation of the Operator
3378 string OperName (Operator oper)
3382 case Operator.Multiply:
3385 case Operator.Division:
3388 case Operator.Modulus:
3391 case Operator.Addition:
3394 case Operator.Subtraction:
3397 case Operator.LeftShift:
3400 case Operator.RightShift:
3403 case Operator.LessThan:
3406 case Operator.GreaterThan:
3409 case Operator.LessThanOrEqual:
3412 case Operator.GreaterThanOrEqual:
3415 case Operator.Equality:
3418 case Operator.Inequality:
3421 case Operator.BitwiseAnd:
3424 case Operator.BitwiseOr:
3427 case Operator.ExclusiveOr:
3430 case Operator.LogicalOr:
3433 case Operator.LogicalAnd:
3437 s = oper.ToString ();
3447 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3449 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3452 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3454 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3458 l = left.Type.GetSignatureForError ();
3459 r = right.Type.GetSignatureForError ();
3461 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3465 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3467 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3470 public override void FlowAnalysis (FlowAnalysisContext fc)
3473 // Optimized version when on-true/on-false data are not needed
3475 if ((oper & Operator.LogicalMask) == 0) {
3476 left.FlowAnalysis (fc);
3477 right.FlowAnalysis (fc);
3481 left.FlowAnalysisConditional (fc);
3482 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3483 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3485 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3486 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3487 right.FlowAnalysisConditional (fc);
3489 if (oper == Operator.LogicalOr)
3490 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3492 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3495 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3497 if ((oper & Operator.LogicalMask) == 0) {
3498 base.FlowAnalysisConditional (fc);
3502 left.FlowAnalysisConditional (fc);
3503 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3504 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3506 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3507 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3508 right.FlowAnalysisConditional (fc);
3510 var lc = left as Constant;
3511 if (oper == Operator.LogicalOr) {
3512 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3513 if (lc != null && lc.IsDefaultValue)
3514 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3516 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3518 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3519 if (lc != null && !lc.IsDefaultValue)
3520 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3522 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3527 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3529 string GetOperatorExpressionTypeName ()
3532 case Operator.Addition:
3533 return IsCompound ? "AddAssign" : "Add";
3534 case Operator.BitwiseAnd:
3535 return IsCompound ? "AndAssign" : "And";
3536 case Operator.BitwiseOr:
3537 return IsCompound ? "OrAssign" : "Or";
3538 case Operator.Division:
3539 return IsCompound ? "DivideAssign" : "Divide";
3540 case Operator.ExclusiveOr:
3541 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3542 case Operator.Equality:
3544 case Operator.GreaterThan:
3545 return "GreaterThan";
3546 case Operator.GreaterThanOrEqual:
3547 return "GreaterThanOrEqual";
3548 case Operator.Inequality:
3550 case Operator.LeftShift:
3551 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3552 case Operator.LessThan:
3554 case Operator.LessThanOrEqual:
3555 return "LessThanOrEqual";
3556 case Operator.LogicalAnd:
3558 case Operator.LogicalOr:
3560 case Operator.Modulus:
3561 return IsCompound ? "ModuloAssign" : "Modulo";
3562 case Operator.Multiply:
3563 return IsCompound ? "MultiplyAssign" : "Multiply";
3564 case Operator.RightShift:
3565 return IsCompound ? "RightShiftAssign" : "RightShift";
3566 case Operator.Subtraction:
3567 return IsCompound ? "SubtractAssign" : "Subtract";
3569 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3573 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3576 case Operator.Addition:
3577 return CSharp.Operator.OpType.Addition;
3578 case Operator.BitwiseAnd:
3579 case Operator.LogicalAnd:
3580 return CSharp.Operator.OpType.BitwiseAnd;
3581 case Operator.BitwiseOr:
3582 case Operator.LogicalOr:
3583 return CSharp.Operator.OpType.BitwiseOr;
3584 case Operator.Division:
3585 return CSharp.Operator.OpType.Division;
3586 case Operator.Equality:
3587 return CSharp.Operator.OpType.Equality;
3588 case Operator.ExclusiveOr:
3589 return CSharp.Operator.OpType.ExclusiveOr;
3590 case Operator.GreaterThan:
3591 return CSharp.Operator.OpType.GreaterThan;
3592 case Operator.GreaterThanOrEqual:
3593 return CSharp.Operator.OpType.GreaterThanOrEqual;
3594 case Operator.Inequality:
3595 return CSharp.Operator.OpType.Inequality;
3596 case Operator.LeftShift:
3597 return CSharp.Operator.OpType.LeftShift;
3598 case Operator.LessThan:
3599 return CSharp.Operator.OpType.LessThan;
3600 case Operator.LessThanOrEqual:
3601 return CSharp.Operator.OpType.LessThanOrEqual;
3602 case Operator.Modulus:
3603 return CSharp.Operator.OpType.Modulus;
3604 case Operator.Multiply:
3605 return CSharp.Operator.OpType.Multiply;
3606 case Operator.RightShift:
3607 return CSharp.Operator.OpType.RightShift;
3608 case Operator.Subtraction:
3609 return CSharp.Operator.OpType.Subtraction;
3611 throw new InternalErrorException (op.ToString ());
3615 public override bool ContainsEmitWithAwait ()
3617 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3620 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3625 case Operator.Multiply:
3626 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3627 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3628 opcode = OpCodes.Mul_Ovf;
3629 else if (!IsFloat (l))
3630 opcode = OpCodes.Mul_Ovf_Un;
3632 opcode = OpCodes.Mul;
3634 opcode = OpCodes.Mul;
3638 case Operator.Division:
3640 opcode = OpCodes.Div_Un;
3642 opcode = OpCodes.Div;
3645 case Operator.Modulus:
3647 opcode = OpCodes.Rem_Un;
3649 opcode = OpCodes.Rem;
3652 case Operator.Addition:
3653 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3654 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3655 opcode = OpCodes.Add_Ovf;
3656 else if (!IsFloat (l))
3657 opcode = OpCodes.Add_Ovf_Un;
3659 opcode = OpCodes.Add;
3661 opcode = OpCodes.Add;
3664 case Operator.Subtraction:
3665 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3666 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3667 opcode = OpCodes.Sub_Ovf;
3668 else if (!IsFloat (l))
3669 opcode = OpCodes.Sub_Ovf_Un;
3671 opcode = OpCodes.Sub;
3673 opcode = OpCodes.Sub;
3676 case Operator.RightShift:
3677 if (!(right is IntConstant)) {
3678 ec.EmitInt (GetShiftMask (l));
3679 ec.Emit (OpCodes.And);
3683 opcode = OpCodes.Shr_Un;
3685 opcode = OpCodes.Shr;
3688 case Operator.LeftShift:
3689 if (!(right is IntConstant)) {
3690 ec.EmitInt (GetShiftMask (l));
3691 ec.Emit (OpCodes.And);
3694 opcode = OpCodes.Shl;
3697 case Operator.Equality:
3698 opcode = OpCodes.Ceq;
3701 case Operator.Inequality:
3702 ec.Emit (OpCodes.Ceq);
3705 opcode = OpCodes.Ceq;
3708 case Operator.LessThan:
3710 opcode = OpCodes.Clt_Un;
3712 opcode = OpCodes.Clt;
3715 case Operator.GreaterThan:
3717 opcode = OpCodes.Cgt_Un;
3719 opcode = OpCodes.Cgt;
3722 case Operator.LessThanOrEqual:
3723 if (IsUnsigned (l) || IsFloat (l))
3724 ec.Emit (OpCodes.Cgt_Un);
3726 ec.Emit (OpCodes.Cgt);
3729 opcode = OpCodes.Ceq;
3732 case Operator.GreaterThanOrEqual:
3733 if (IsUnsigned (l) || IsFloat (l))
3734 ec.Emit (OpCodes.Clt_Un);
3736 ec.Emit (OpCodes.Clt);
3740 opcode = OpCodes.Ceq;
3743 case Operator.BitwiseOr:
3744 opcode = OpCodes.Or;
3747 case Operator.BitwiseAnd:
3748 opcode = OpCodes.And;
3751 case Operator.ExclusiveOr:
3752 opcode = OpCodes.Xor;
3756 throw new InternalErrorException (oper.ToString ());
3762 static int GetShiftMask (TypeSpec type)
3764 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3767 static bool IsUnsigned (TypeSpec t)
3769 switch (t.BuiltinType) {
3770 case BuiltinTypeSpec.Type.Char:
3771 case BuiltinTypeSpec.Type.UInt:
3772 case BuiltinTypeSpec.Type.ULong:
3773 case BuiltinTypeSpec.Type.UShort:
3774 case BuiltinTypeSpec.Type.Byte:
3781 static bool IsFloat (TypeSpec t)
3783 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3786 public Expression ResolveOperator (ResolveContext rc)
3788 eclass = ExprClass.Value;
3790 TypeSpec l = left.Type;
3791 TypeSpec r = right.Type;
3793 bool primitives_only = false;
3796 // Handles predefined primitive types
3798 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3799 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3800 if ((oper & Operator.ShiftMask) == 0) {
3801 if (!DoBinaryOperatorPromotion (rc))
3804 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3808 if (l.IsPointer || r.IsPointer)
3809 return ResolveOperatorPointer (rc, l, r);
3812 if ((state & State.UserOperatorsExcluded) == 0) {
3813 expr = ResolveUserOperator (rc, left, right);
3818 bool lenum = l.IsEnum;
3819 bool renum = r.IsEnum;
3820 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3824 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3825 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3830 if ((oper & Operator.BitwiseMask) != 0) {
3831 expr = EmptyCast.Create (expr, type);
3832 enum_conversion = GetEnumResultCast (type);
3834 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3835 expr = OptimizeAndOperation (expr);
3839 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3840 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3843 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3844 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3848 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3851 // We cannot break here there is also Enum + String possible match
3852 // which is not ambiguous with predefined enum operators
3855 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3856 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3860 } else if (l.IsDelegate || r.IsDelegate) {
3864 expr = ResolveOperatorDelegate (rc, l, r);
3866 // TODO: Can this be ambiguous
3874 // Equality operators are more complicated
3876 if ((oper & Operator.EqualityMask) != 0) {
3877 return ResolveEquality (rc, l, r, primitives_only);
3880 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3884 if (primitives_only)
3888 // Lifted operators have lower priority
3890 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3893 static bool IsEnumOrNullableEnum (TypeSpec type)
3895 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3899 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3900 // if 'left' is not an enumeration constant, create one from the type of 'right'
3901 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3904 case Operator.BitwiseOr:
3905 case Operator.BitwiseAnd:
3906 case Operator.ExclusiveOr:
3907 case Operator.Equality:
3908 case Operator.Inequality:
3909 case Operator.LessThan:
3910 case Operator.LessThanOrEqual:
3911 case Operator.GreaterThan:
3912 case Operator.GreaterThanOrEqual:
3913 if (left.Type.IsEnum)
3916 if (left.IsZeroInteger)
3917 return left.Reduce (ec, right.Type);
3921 case Operator.Addition:
3922 case Operator.Subtraction:
3925 case Operator.Multiply:
3926 case Operator.Division:
3927 case Operator.Modulus:
3928 case Operator.LeftShift:
3929 case Operator.RightShift:
3930 if (right.Type.IsEnum || left.Type.IsEnum)
3939 // The `|' operator used on types which were extended is dangerous
3941 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3943 OpcodeCast lcast = left as OpcodeCast;
3944 if (lcast != null) {
3945 if (IsUnsigned (lcast.UnderlyingType))
3949 OpcodeCast rcast = right as OpcodeCast;
3950 if (rcast != null) {
3951 if (IsUnsigned (rcast.UnderlyingType))
3955 if (lcast == null && rcast == null)
3958 // FIXME: consider constants
3960 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3961 ec.Report.Warning (675, 3, loc,
3962 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3963 ltype.GetSignatureForError ());
3966 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3968 return new PredefinedOperator[] {
3970 // Pointer arithmetic:
3972 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3973 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3974 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3975 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3977 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3978 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3979 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3980 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3983 // T* operator + (int y, T* x);
3984 // T* operator + (uint y, T *x);
3985 // T* operator + (long y, T *x);
3986 // T* operator + (ulong y, T *x);
3988 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3989 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3990 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3991 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3994 // long operator - (T* x, T *y)
3996 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
4000 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
4002 TypeSpec bool_type = types.Bool;
4005 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4006 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
4007 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
4008 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
4009 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
4010 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
4011 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
4013 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
4014 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
4015 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
4016 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
4017 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
4018 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
4019 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
4021 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
4022 // Remaining string operators are in lifted tables
4024 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
4026 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
4027 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
4028 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
4032 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
4034 var types = module.Compiler.BuiltinTypes;
4037 // Not strictly lifted but need to be in second group otherwise expressions like
4038 // int + null would resolve to +(object, string) instead of +(int?, int?)
4040 var string_operators = new [] {
4041 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
4042 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
4045 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4046 if (nullable == null)
4047 return string_operators;
4049 var bool_type = types.Bool;
4051 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
4052 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4053 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4054 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4055 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4056 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4057 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4058 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4061 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4062 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4063 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4064 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4065 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4066 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4067 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4069 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4070 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4071 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4072 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4073 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4074 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4075 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4077 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4079 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4080 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4081 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4083 string_operators [0],
4084 string_operators [1]
4088 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4090 TypeSpec bool_type = types.Bool;
4093 new PredefinedEqualityOperator (types.String, bool_type),
4094 new PredefinedEqualityOperator (types.Delegate, bool_type),
4095 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4096 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4097 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4098 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4099 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4100 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4101 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4102 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4106 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4108 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4110 if (nullable == null)
4111 return new PredefinedOperator [0];
4113 var types = module.Compiler.BuiltinTypes;
4114 var bool_type = types.Bool;
4115 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4116 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4117 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4118 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4119 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4120 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4121 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4122 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4125 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4126 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4127 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4128 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4129 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4130 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4131 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4132 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4137 // 7.2.6.2 Binary numeric promotions
4139 bool DoBinaryOperatorPromotion (ResolveContext rc)
4141 TypeSpec ltype = left.Type;
4142 if (ltype.IsNullableType) {
4143 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4147 // This is numeric promotion code only
4149 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4152 TypeSpec rtype = right.Type;
4153 if (rtype.IsNullableType) {
4154 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4157 var lb = ltype.BuiltinType;
4158 var rb = rtype.BuiltinType;
4162 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4163 type = rc.BuiltinTypes.Decimal;
4164 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4165 type = rc.BuiltinTypes.Double;
4166 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4167 type = rc.BuiltinTypes.Float;
4168 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4169 type = rc.BuiltinTypes.ULong;
4171 if (IsSignedType (lb)) {
4172 expr = ConvertSignedConstant (left, type);
4176 } else if (IsSignedType (rb)) {
4177 expr = ConvertSignedConstant (right, type);
4183 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4184 type = rc.BuiltinTypes.Long;
4185 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4186 type = rc.BuiltinTypes.UInt;
4188 if (IsSignedType (lb)) {
4189 expr = ConvertSignedConstant (left, type);
4191 type = rc.BuiltinTypes.Long;
4192 } else if (IsSignedType (rb)) {
4193 expr = ConvertSignedConstant (right, type);
4195 type = rc.BuiltinTypes.Long;
4198 type = rc.BuiltinTypes.Int;
4201 if (ltype != type) {
4202 expr = PromoteExpression (rc, left, type);
4209 if (rtype != type) {
4210 expr = PromoteExpression (rc, right, type);
4220 static bool IsSignedType (BuiltinTypeSpec.Type type)
4223 case BuiltinTypeSpec.Type.Int:
4224 case BuiltinTypeSpec.Type.Short:
4225 case BuiltinTypeSpec.Type.SByte:
4226 case BuiltinTypeSpec.Type.Long:
4233 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4235 var c = expr as Constant;
4239 return c.ConvertImplicitly (type);
4242 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4244 if (expr.Type.IsNullableType) {
4245 return Convert.ImplicitConversionStandard (rc, expr,
4246 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4249 var c = expr as Constant;
4251 return c.ConvertImplicitly (type);
4253 return Convert.ImplicitNumericConversion (expr, type);
4256 protected override Expression DoResolve (ResolveContext ec)
4261 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4262 left = ((ParenthesizedExpression) left).Expr;
4263 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4267 if (left.eclass == ExprClass.Type) {
4268 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4272 left = left.Resolve (ec);
4277 right = right.Resolve (ec);
4281 Constant lc = left as Constant;
4282 Constant rc = right as Constant;
4284 // The conversion rules are ignored in enum context but why
4285 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4286 lc = EnumLiftUp (ec, lc, rc);
4288 rc = EnumLiftUp (ec, rc, lc);
4291 if (rc != null && lc != null) {
4292 int prev_e = ec.Report.Errors;
4293 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4294 if (e != null || ec.Report.Errors != prev_e)
4298 // Comparison warnings
4299 if ((oper & Operator.ComparisonMask) != 0) {
4300 if (left.Equals (right)) {
4301 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4303 CheckOutOfRangeComparison (ec, lc, right.Type);
4304 CheckOutOfRangeComparison (ec, rc, left.Type);
4307 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4308 return DoResolveDynamic (ec);
4310 return DoResolveCore (ec, left, right);
4313 Expression DoResolveDynamic (ResolveContext rc)
4316 var rt = right.Type;
4317 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4318 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4319 Error_OperatorCannotBeApplied (rc, left, right);
4326 // Special handling for logical boolean operators which require rhs not to be
4327 // evaluated based on lhs value
4329 if ((oper & Operator.LogicalMask) != 0) {
4330 Expression cond_left, cond_right, expr;
4332 args = new Arguments (2);
4334 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4335 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4337 var cond_args = new Arguments (1);
4338 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4341 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4342 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4344 left = temp.CreateReferenceExpression (rc, loc);
4345 if (oper == Operator.LogicalAnd) {
4346 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4349 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4353 args.Add (new Argument (left));
4354 args.Add (new Argument (right));
4355 cond_right = new DynamicExpressionStatement (this, args, loc);
4357 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4359 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4360 rc.Report.Error (7083, left.Location,
4361 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4362 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4366 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4367 args.Add (new Argument (right));
4368 right = new DynamicExpressionStatement (this, args, loc);
4371 // bool && dynamic => (temp = left) ? temp && right : temp;
4372 // bool || dynamic => (temp = left) ? temp : temp || right;
4374 if (oper == Operator.LogicalAnd) {
4376 cond_right = temp.CreateReferenceExpression (rc, loc);
4378 cond_left = temp.CreateReferenceExpression (rc, loc);
4382 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4385 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4388 args = new Arguments (2);
4389 args.Add (new Argument (left));
4390 args.Add (new Argument (right));
4391 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4394 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4396 Expression expr = ResolveOperator (ec);
4398 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4400 if (left == null || right == null)
4401 throw new InternalErrorException ("Invalid conversion");
4403 if (oper == Operator.BitwiseOr)
4404 CheckBitwiseOrOnSignExtended (ec);
4409 public override SLE.Expression MakeExpression (BuilderContext ctx)
4411 return MakeExpression (ctx, left, right);
4414 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4416 var le = left.MakeExpression (ctx);
4417 var re = right.MakeExpression (ctx);
4418 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4421 case Operator.Addition:
4422 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4423 case Operator.BitwiseAnd:
4424 return SLE.Expression.And (le, re);
4425 case Operator.BitwiseOr:
4426 return SLE.Expression.Or (le, re);
4427 case Operator.Division:
4428 return SLE.Expression.Divide (le, re);
4429 case Operator.Equality:
4430 return SLE.Expression.Equal (le, re);
4431 case Operator.ExclusiveOr:
4432 return SLE.Expression.ExclusiveOr (le, re);
4433 case Operator.GreaterThan:
4434 return SLE.Expression.GreaterThan (le, re);
4435 case Operator.GreaterThanOrEqual:
4436 return SLE.Expression.GreaterThanOrEqual (le, re);
4437 case Operator.Inequality:
4438 return SLE.Expression.NotEqual (le, re);
4439 case Operator.LeftShift:
4440 return SLE.Expression.LeftShift (le, re);
4441 case Operator.LessThan:
4442 return SLE.Expression.LessThan (le, re);
4443 case Operator.LessThanOrEqual:
4444 return SLE.Expression.LessThanOrEqual (le, re);
4445 case Operator.LogicalAnd:
4446 return SLE.Expression.AndAlso (le, re);
4447 case Operator.LogicalOr:
4448 return SLE.Expression.OrElse (le, re);
4449 case Operator.Modulus:
4450 return SLE.Expression.Modulo (le, re);
4451 case Operator.Multiply:
4452 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4453 case Operator.RightShift:
4454 return SLE.Expression.RightShift (le, re);
4455 case Operator.Subtraction:
4456 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4458 throw new NotImplementedException (oper.ToString ());
4463 // D operator + (D x, D y)
4464 // D operator - (D x, D y)
4466 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4468 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4470 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4471 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4476 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4477 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4487 MethodSpec method = null;
4488 Arguments args = new Arguments (2);
4489 args.Add (new Argument (left));
4490 args.Add (new Argument (right));
4492 if (oper == Operator.Addition) {
4493 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4494 } else if (oper == Operator.Subtraction) {
4495 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4499 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4501 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4502 return new ClassCast (expr, l);
4506 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4508 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4511 // bool operator == (E x, E y);
4512 // bool operator != (E x, E y);
4513 // bool operator < (E x, E y);
4514 // bool operator > (E x, E y);
4515 // bool operator <= (E x, E y);
4516 // bool operator >= (E x, E y);
4518 // E operator & (E x, E y);
4519 // E operator | (E x, E y);
4520 // E operator ^ (E x, E y);
4523 if ((oper & Operator.ComparisonMask) != 0) {
4524 type = rc.BuiltinTypes.Bool;
4530 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4536 if (ltype == rtype) {
4540 var lifted = new Nullable.LiftedBinaryOperator (this);
4542 lifted.Right = right;
4543 return lifted.Resolve (rc);
4546 if (renum && !ltype.IsNullableType) {
4547 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4552 } else if (lenum && !rtype.IsNullableType) {
4553 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4561 // Now try lifted version of predefined operator
4563 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4564 if (nullable_type != null) {
4565 if (renum && !ltype.IsNullableType) {
4566 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4568 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4571 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4574 if ((oper & Operator.BitwiseMask) != 0)
4578 if ((oper & Operator.BitwiseMask) != 0)
4579 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4581 return CreateLiftedValueTypeResult (rc, rtype);
4585 var lifted = new Nullable.LiftedBinaryOperator (this);
4587 lifted.Right = right;
4588 return lifted.Resolve (rc);
4590 } else if (lenum && !rtype.IsNullableType) {
4591 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4593 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4596 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4599 if ((oper & Operator.BitwiseMask) != 0)
4603 if ((oper & Operator.BitwiseMask) != 0)
4604 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4606 return CreateLiftedValueTypeResult (rc, ltype);
4610 var lifted = new Nullable.LiftedBinaryOperator (this);
4612 lifted.Right = expr;
4613 return lifted.Resolve (rc);
4615 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4616 Nullable.Unwrap unwrap = null;
4617 if (left.IsNull || right.IsNull) {
4618 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4619 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4621 if ((oper & Operator.RelationalMask) != 0)
4622 return CreateLiftedValueTypeResult (rc, rtype);
4624 if ((oper & Operator.BitwiseMask) != 0)
4625 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4628 return CreateLiftedValueTypeResult (rc, left.Type);
4630 // Equality operators are valid between E? and null
4632 unwrap = new Nullable.Unwrap (right);
4634 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4638 if ((oper & Operator.BitwiseMask) != 0)
4643 var lifted = new Nullable.LiftedBinaryOperator (this);
4645 lifted.Right = right;
4646 lifted.UnwrapRight = unwrap;
4647 return lifted.Resolve (rc);
4649 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4650 Nullable.Unwrap unwrap = null;
4651 if (right.IsNull || left.IsNull) {
4652 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4653 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4655 if ((oper & Operator.RelationalMask) != 0)
4656 return CreateLiftedValueTypeResult (rc, ltype);
4658 if ((oper & Operator.BitwiseMask) != 0)
4659 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4662 return CreateLiftedValueTypeResult (rc, right.Type);
4664 // Equality operators are valid between E? and null
4666 unwrap = new Nullable.Unwrap (left);
4668 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4672 if ((oper & Operator.BitwiseMask) != 0)
4677 var lifted = new Nullable.LiftedBinaryOperator (this);
4679 lifted.UnwrapLeft = unwrap;
4680 lifted.Right = expr;
4681 return lifted.Resolve (rc);
4689 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4691 TypeSpec underlying_type;
4692 if (expr.Type.IsNullableType) {
4693 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4695 underlying_type = EnumSpec.GetUnderlyingType (nt);
4697 underlying_type = nt;
4698 } else if (expr.Type.IsEnum) {
4699 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4701 underlying_type = expr.Type;
4704 switch (underlying_type.BuiltinType) {
4705 case BuiltinTypeSpec.Type.SByte:
4706 case BuiltinTypeSpec.Type.Byte:
4707 case BuiltinTypeSpec.Type.Short:
4708 case BuiltinTypeSpec.Type.UShort:
4709 underlying_type = rc.BuiltinTypes.Int;
4713 if (expr.Type.IsNullableType || liftType)
4714 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4716 if (expr.Type == underlying_type)
4719 return EmptyCast.Create (expr, underlying_type);
4722 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4725 // U operator - (E e, E f)
4726 // E operator - (E e, U x) // Internal decomposition operator
4727 // E operator - (U x, E e) // Internal decomposition operator
4729 // E operator + (E e, U x)
4730 // E operator + (U x, E e)
4739 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4745 if (!enum_type.IsNullableType) {
4746 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4748 if (oper == Operator.Subtraction)
4749 expr = ConvertEnumSubtractionResult (rc, expr);
4751 expr = ConvertEnumAdditionalResult (expr, enum_type);
4753 enum_conversion = GetEnumResultCast (expr.Type);
4758 var nullable = rc.Module.PredefinedTypes.Nullable;
4761 // Don't try nullable version when nullable type is undefined
4763 if (!nullable.IsDefined)
4766 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4769 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4771 if (oper == Operator.Subtraction)
4772 expr = ConvertEnumSubtractionResult (rc, expr);
4774 expr = ConvertEnumAdditionalResult (expr, enum_type);
4776 enum_conversion = GetEnumResultCast (expr.Type);
4782 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4784 return EmptyCast.Create (expr, enumType);
4787 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4790 // Enumeration subtraction has different result type based on
4793 TypeSpec result_type;
4794 if (left.Type == right.Type) {
4795 var c = right as EnumConstant;
4796 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4798 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4799 // E which is not what expressions E - 1 or 0 - E return
4801 result_type = left.Type;
4803 result_type = left.Type.IsNullableType ?
4804 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4805 EnumSpec.GetUnderlyingType (left.Type);
4808 if (IsEnumOrNullableEnum (left.Type)) {
4809 result_type = left.Type;
4811 result_type = right.Type;
4814 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4815 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4818 return EmptyCast.Create (expr, result_type);
4821 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4823 if (type.IsNullableType)
4824 type = Nullable.NullableInfo.GetUnderlyingType (type);
4827 type = EnumSpec.GetUnderlyingType (type);
4829 switch (type.BuiltinType) {
4830 case BuiltinTypeSpec.Type.SByte:
4831 return ConvCast.Mode.I4_I1;
4832 case BuiltinTypeSpec.Type.Byte:
4833 return ConvCast.Mode.I4_U1;
4834 case BuiltinTypeSpec.Type.Short:
4835 return ConvCast.Mode.I4_I2;
4836 case BuiltinTypeSpec.Type.UShort:
4837 return ConvCast.Mode.I4_U2;
4844 // Equality operators rules
4846 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4849 type = ec.BuiltinTypes.Bool;
4850 bool no_arg_conv = false;
4852 if (!primitives_only) {
4855 // a, Both operands are reference-type values or the value null
4856 // b, One operand is a value of type T where T is a type-parameter and
4857 // the other operand is the value null. Furthermore T does not have the
4858 // value type constraint
4860 // LAMESPEC: Very confusing details in the specification, basically any
4861 // reference like type-parameter is allowed
4863 var tparam_l = l as TypeParameterSpec;
4864 var tparam_r = r as TypeParameterSpec;
4865 if (tparam_l != null) {
4866 if (right is NullLiteral) {
4867 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4870 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4874 if (!tparam_l.IsReferenceType)
4877 l = tparam_l.GetEffectiveBase ();
4878 left = new BoxedCast (left, l);
4879 } else if (left is NullLiteral && tparam_r == null) {
4880 if (TypeSpec.IsReferenceType (r))
4883 if (r.Kind == MemberKind.InternalCompilerType)
4887 if (tparam_r != null) {
4888 if (left is NullLiteral) {
4889 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4892 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4896 if (!tparam_r.IsReferenceType)
4899 r = tparam_r.GetEffectiveBase ();
4900 right = new BoxedCast (right, r);
4901 } else if (right is NullLiteral) {
4902 if (TypeSpec.IsReferenceType (l))
4905 if (l.Kind == MemberKind.InternalCompilerType)
4910 // LAMESPEC: method groups can be compared when they convert to other side delegate
4913 if (right.eclass == ExprClass.MethodGroup) {
4914 result = Convert.ImplicitConversion (ec, right, l, loc);
4920 } else if (r.IsDelegate && l != r) {
4923 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4924 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4931 no_arg_conv = l == r && !l.IsStruct;
4936 // bool operator != (string a, string b)
4937 // bool operator == (string a, string b)
4939 // bool operator != (Delegate a, Delegate b)
4940 // bool operator == (Delegate a, Delegate b)
4942 // bool operator != (bool a, bool b)
4943 // bool operator == (bool a, bool b)
4945 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4946 // they implement an implicit conversion to any of types above. This does
4947 // not apply when both operands are of same reference type
4949 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4950 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4955 // Now try lifted version of predefined operators
4957 if (no_arg_conv && !l.IsNullableType) {
4959 // Optimizes cases which won't match
4962 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4968 // The == and != operators permit one operand to be a value of a nullable
4969 // type and the other to be the null literal, even if no predefined or user-defined
4970 // operator (in unlifted or lifted form) exists for the operation.
4972 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4973 var lifted = new Nullable.LiftedBinaryOperator (this);
4975 lifted.Right = right;
4976 return lifted.Resolve (ec);
4981 // bool operator != (object a, object b)
4982 // bool operator == (object a, object b)
4984 // An explicit reference conversion exists from the
4985 // type of either operand to the type of the other operand.
4988 // Optimize common path
4990 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4993 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4994 !Convert.ExplicitReferenceConversionExists (r, l))
4997 // Reject allowed explicit conversions like int->object
4998 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
5001 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
5002 ec.Report.Warning (253, 2, loc,
5003 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
5004 l.GetSignatureForError ());
5006 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
5007 ec.Report.Warning (252, 2, loc,
5008 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
5009 r.GetSignatureForError ());
5015 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
5018 // bool operator == (void* x, void* y);
5019 // bool operator != (void* x, void* y);
5020 // bool operator < (void* x, void* y);
5021 // bool operator > (void* x, void* y);
5022 // bool operator <= (void* x, void* y);
5023 // bool operator >= (void* x, void* y);
5025 if ((oper & Operator.ComparisonMask) != 0) {
5028 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
5035 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
5041 type = ec.BuiltinTypes.Bool;
5045 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
5049 // Build-in operators method overloading
5051 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
5053 PredefinedOperator best_operator = null;
5054 TypeSpec l = left.Type;
5055 TypeSpec r = right.Type;
5056 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5058 foreach (PredefinedOperator po in operators) {
5059 if ((po.OperatorsMask & oper_mask) == 0)
5062 if (primitives_only) {
5063 if (!po.IsPrimitiveApplicable (l, r))
5066 if (!po.IsApplicable (ec, left, right))
5070 if (best_operator == null) {
5072 if (primitives_only)
5078 best_operator = po.ResolveBetterOperator (ec, best_operator);
5080 if (best_operator == null) {
5081 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5082 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5089 if (best_operator == null)
5092 return best_operator.ConvertResult (ec, this);
5096 // Optimize & constant expressions with 0 value
5098 Expression OptimizeAndOperation (Expression expr)
5100 Constant rc = right as Constant;
5101 Constant lc = left as Constant;
5102 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5104 // The result is a constant with side-effect
5106 Constant side_effect = rc == null ?
5107 new SideEffectConstant (lc, right, loc) :
5108 new SideEffectConstant (rc, left, loc);
5110 return ReducedExpression.Create (side_effect, expr);
5117 // Value types can be compared with the null literal because of the lifting
5118 // language rules. However the result is always true or false.
5120 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5122 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5123 type = rc.BuiltinTypes.Bool;
5127 // FIXME: Handle side effect constants
5128 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5130 if ((Oper & Operator.EqualityMask) != 0) {
5131 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5132 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5134 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5135 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5142 // Performs user-operator overloading
5144 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5146 Expression oper_expr;
5148 var op = ConvertBinaryToUserOperator (oper);
5150 if (l.IsNullableType)
5151 l = Nullable.NullableInfo.GetUnderlyingType (l);
5153 if (r.IsNullableType)
5154 r = Nullable.NullableInfo.GetUnderlyingType (r);
5156 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5157 IList<MemberSpec> right_operators = null;
5160 right_operators = MemberCache.GetUserOperator (r, op, false);
5161 if (right_operators == null && left_operators == null)
5163 } else if (left_operators == null) {
5167 Arguments args = new Arguments (2);
5168 Argument larg = new Argument (left);
5170 Argument rarg = new Argument (right);
5174 // User-defined operator implementations always take precedence
5175 // over predefined operator implementations
5177 if (left_operators != null && right_operators != null) {
5178 left_operators = CombineUserOperators (left_operators, right_operators);
5179 } else if (right_operators != null) {
5180 left_operators = right_operators;
5183 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5184 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5186 var res = new OverloadResolver (left_operators, restr, loc);
5188 var oper_method = res.ResolveOperator (rc, ref args);
5189 if (oper_method == null) {
5191 // Logical && and || cannot be lifted
5193 if ((oper & Operator.LogicalMask) != 0)
5197 // Apply lifted user operators only for liftable types. Implicit conversion
5198 // to nullable types is not allowed
5200 if (!IsLiftedOperatorApplicable ())
5203 // TODO: Cache the result in module container
5204 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5205 if (lifted_methods == null)
5208 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5210 oper_method = res.ResolveOperator (rc, ref args);
5211 if (oper_method == null)
5214 MethodSpec best_original = null;
5215 foreach (MethodSpec ms in left_operators) {
5216 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5222 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5224 // Expression trees use lifted notation in this case
5226 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5227 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5230 var ptypes = best_original.Parameters.Types;
5232 if (left.IsNull || right.IsNull) {
5234 // The lifted operator produces a null value if one or both operands are null
5236 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5237 type = oper_method.ReturnType;
5238 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5242 // The lifted operator produces the value false if one or both operands are null for
5243 // relational operators.
5245 if ((oper & Operator.RelationalMask) != 0) {
5247 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5248 // because return type is actually bool
5250 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5253 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5254 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5258 type = oper_method.ReturnType;
5259 var lifted = new Nullable.LiftedBinaryOperator (this);
5260 lifted.UserOperator = best_original;
5262 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5263 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5266 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5267 lifted.UnwrapRight = new Nullable.Unwrap (right);
5270 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5271 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5273 return lifted.Resolve (rc);
5276 if ((oper & Operator.LogicalMask) != 0) {
5277 // TODO: CreateExpressionTree is allocated every time
5278 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5279 oper == Operator.LogicalAnd, loc).Resolve (rc);
5281 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5284 this.left = larg.Expr;
5285 this.right = rarg.Expr;
5290 bool IsLiftedOperatorApplicable ()
5292 if (left.Type.IsNullableType) {
5293 if ((oper & Operator.EqualityMask) != 0)
5294 return !right.IsNull;
5299 if (right.Type.IsNullableType) {
5300 if ((oper & Operator.EqualityMask) != 0)
5301 return !left.IsNull;
5306 if (TypeSpec.IsValueType (left.Type))
5307 return right.IsNull;
5309 if (TypeSpec.IsValueType (right.Type))
5315 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5317 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5318 if (nullable_type == null)
5322 // Lifted operators permit predefined and user-defined operators that operate
5323 // on non-nullable value types to also be used with nullable forms of those types.
5324 // Lifted operators are constructed from predefined and user-defined operators
5325 // that meet certain requirements
5327 List<MemberSpec> lifted = null;
5328 foreach (MethodSpec oper in operators) {
5330 if ((Oper & Operator.ComparisonMask) != 0) {
5332 // Result type must be of type bool for lifted comparison operators
5334 rt = oper.ReturnType;
5335 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5338 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5344 var ptypes = oper.Parameters.Types;
5345 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5349 // LAMESPEC: I am not sure why but for equality operators to be lifted
5350 // both types have to match
5352 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5356 lifted = new List<MemberSpec> ();
5359 // The lifted form is constructed by adding a single ? modifier to each operand and
5360 // result type except for comparison operators where return type is bool
5363 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5365 var parameters = ParametersCompiled.CreateFullyResolved (
5366 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5367 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5369 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5370 rt, parameters, oper.Modifiers);
5372 lifted.Add (lifted_op);
5379 // Merge two sets of user operators into one, they are mostly distinguish
5380 // except when they share base type and it contains an operator
5382 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5384 var combined = new List<MemberSpec> (left.Count + right.Count);
5385 combined.AddRange (left);
5386 foreach (var r in right) {
5388 foreach (var l in left) {
5389 if (l.DeclaringType == r.DeclaringType) {
5402 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5404 if (c is IntegralConstant || c is CharConstant) {
5406 c.ConvertExplicitly (true, type);
5407 } catch (OverflowException) {
5408 ec.Report.Warning (652, 2, loc,
5409 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5410 type.GetSignatureForError ());
5416 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5417 /// context of a conditional bool expression. This function will return
5418 /// false if it is was possible to use EmitBranchable, or true if it was.
5420 /// The expression's code is generated, and we will generate a branch to `target'
5421 /// if the resulting expression value is equal to isTrue
5423 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5425 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5426 left = left.EmitToField (ec);
5428 if ((oper & Operator.LogicalMask) == 0) {
5429 right = right.EmitToField (ec);
5434 // This is more complicated than it looks, but its just to avoid
5435 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5436 // but on top of that we want for == and != to use a special path
5437 // if we are comparing against null
5439 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5440 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5443 // put the constant on the rhs, for simplicity
5445 if (left is Constant) {
5446 Expression swap = right;
5452 // brtrue/brfalse works with native int only
5454 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5455 left.EmitBranchable (ec, target, my_on_true);
5458 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5459 // right is a boolean, and it's not 'false' => it is 'true'
5460 left.EmitBranchable (ec, target, !my_on_true);
5464 } else if (oper == Operator.LogicalAnd) {
5467 Label tests_end = ec.DefineLabel ();
5469 left.EmitBranchable (ec, tests_end, false);
5470 right.EmitBranchable (ec, target, true);
5471 ec.MarkLabel (tests_end);
5474 // This optimizes code like this
5475 // if (true && i > 4)
5477 if (!(left is Constant))
5478 left.EmitBranchable (ec, target, false);
5480 if (!(right is Constant))
5481 right.EmitBranchable (ec, target, false);
5486 } else if (oper == Operator.LogicalOr){
5488 left.EmitBranchable (ec, target, true);
5489 right.EmitBranchable (ec, target, true);
5492 Label tests_end = ec.DefineLabel ();
5493 left.EmitBranchable (ec, tests_end, true);
5494 right.EmitBranchable (ec, target, false);
5495 ec.MarkLabel (tests_end);
5500 } else if ((oper & Operator.ComparisonMask) == 0) {
5501 base.EmitBranchable (ec, target, on_true);
5508 TypeSpec t = left.Type;
5509 bool is_float = IsFloat (t);
5510 bool is_unsigned = is_float || IsUnsigned (t);
5513 case Operator.Equality:
5515 ec.Emit (OpCodes.Beq, target);
5517 ec.Emit (OpCodes.Bne_Un, target);
5520 case Operator.Inequality:
5522 ec.Emit (OpCodes.Bne_Un, target);
5524 ec.Emit (OpCodes.Beq, target);
5527 case Operator.LessThan:
5529 if (is_unsigned && !is_float)
5530 ec.Emit (OpCodes.Blt_Un, target);
5532 ec.Emit (OpCodes.Blt, target);
5535 ec.Emit (OpCodes.Bge_Un, target);
5537 ec.Emit (OpCodes.Bge, target);
5540 case Operator.GreaterThan:
5542 if (is_unsigned && !is_float)
5543 ec.Emit (OpCodes.Bgt_Un, target);
5545 ec.Emit (OpCodes.Bgt, target);
5548 ec.Emit (OpCodes.Ble_Un, target);
5550 ec.Emit (OpCodes.Ble, target);
5553 case Operator.LessThanOrEqual:
5555 if (is_unsigned && !is_float)
5556 ec.Emit (OpCodes.Ble_Un, target);
5558 ec.Emit (OpCodes.Ble, target);
5561 ec.Emit (OpCodes.Bgt_Un, target);
5563 ec.Emit (OpCodes.Bgt, target);
5567 case Operator.GreaterThanOrEqual:
5569 if (is_unsigned && !is_float)
5570 ec.Emit (OpCodes.Bge_Un, target);
5572 ec.Emit (OpCodes.Bge, target);
5575 ec.Emit (OpCodes.Blt_Un, target);
5577 ec.Emit (OpCodes.Blt, target);
5580 throw new InternalErrorException (oper.ToString ());
5584 public override void Emit (EmitContext ec)
5586 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5587 left = left.EmitToField (ec);
5589 if ((oper & Operator.LogicalMask) == 0) {
5590 right = right.EmitToField (ec);
5595 // Handle short-circuit operators differently
5598 if ((oper & Operator.LogicalMask) != 0) {
5599 Label load_result = ec.DefineLabel ();
5600 Label end = ec.DefineLabel ();
5602 bool is_or = oper == Operator.LogicalOr;
5603 left.EmitBranchable (ec, load_result, is_or);
5605 ec.Emit (OpCodes.Br_S, end);
5607 ec.MarkLabel (load_result);
5608 ec.EmitInt (is_or ? 1 : 0);
5614 // Optimize zero-based operations which cannot be optimized at expression level
5616 if (oper == Operator.Subtraction) {
5617 var lc = left as IntegralConstant;
5618 if (lc != null && lc.IsDefaultValue) {
5620 ec.Emit (OpCodes.Neg);
5625 EmitOperator (ec, left, right);
5628 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5633 EmitOperatorOpcode (ec, oper, left.Type, right);
5636 // Emit result enumerable conversion this way because it's quite complicated get it
5637 // to resolved tree because expression tree cannot see it.
5639 if (enum_conversion != 0)
5640 ConvCast.Emit (ec, enum_conversion);
5643 public override void EmitSideEffect (EmitContext ec)
5645 if ((oper & Operator.LogicalMask) != 0 ||
5646 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5647 base.EmitSideEffect (ec);
5649 left.EmitSideEffect (ec);
5650 right.EmitSideEffect (ec);
5654 public override Expression EmitToField (EmitContext ec)
5656 if ((oper & Operator.LogicalMask) == 0) {
5657 var await_expr = left as Await;
5658 if (await_expr != null && right.IsSideEffectFree) {
5659 await_expr.Statement.EmitPrologue (ec);
5660 left = await_expr.Statement.GetResultExpression (ec);
5664 await_expr = right as Await;
5665 if (await_expr != null && left.IsSideEffectFree) {
5666 await_expr.Statement.EmitPrologue (ec);
5667 right = await_expr.Statement.GetResultExpression (ec);
5672 return base.EmitToField (ec);
5675 protected override void CloneTo (CloneContext clonectx, Expression t)
5677 Binary target = (Binary) t;
5679 target.left = left.Clone (clonectx);
5680 target.right = right.Clone (clonectx);
5683 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5685 Arguments binder_args = new Arguments (4);
5687 MemberAccess sle = new MemberAccess (new MemberAccess (
5688 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5690 CSharpBinderFlags flags = 0;
5691 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5692 flags = CSharpBinderFlags.CheckedContext;
5694 if ((oper & Operator.LogicalMask) != 0)
5695 flags |= CSharpBinderFlags.BinaryOperationLogical;
5697 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5698 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5699 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5700 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5702 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5705 public override Expression CreateExpressionTree (ResolveContext ec)
5707 return CreateExpressionTree (ec, null);
5710 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5713 bool lift_arg = false;
5716 case Operator.Addition:
5717 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5718 method_name = "AddChecked";
5720 method_name = "Add";
5722 case Operator.BitwiseAnd:
5723 method_name = "And";
5725 case Operator.BitwiseOr:
5728 case Operator.Division:
5729 method_name = "Divide";
5731 case Operator.Equality:
5732 method_name = "Equal";
5735 case Operator.ExclusiveOr:
5736 method_name = "ExclusiveOr";
5738 case Operator.GreaterThan:
5739 method_name = "GreaterThan";
5742 case Operator.GreaterThanOrEqual:
5743 method_name = "GreaterThanOrEqual";
5746 case Operator.Inequality:
5747 method_name = "NotEqual";
5750 case Operator.LeftShift:
5751 method_name = "LeftShift";
5753 case Operator.LessThan:
5754 method_name = "LessThan";
5757 case Operator.LessThanOrEqual:
5758 method_name = "LessThanOrEqual";
5761 case Operator.LogicalAnd:
5762 method_name = "AndAlso";
5764 case Operator.LogicalOr:
5765 method_name = "OrElse";
5767 case Operator.Modulus:
5768 method_name = "Modulo";
5770 case Operator.Multiply:
5771 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5772 method_name = "MultiplyChecked";
5774 method_name = "Multiply";
5776 case Operator.RightShift:
5777 method_name = "RightShift";
5779 case Operator.Subtraction:
5780 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5781 method_name = "SubtractChecked";
5783 method_name = "Subtract";
5787 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5790 Arguments args = new Arguments (2);
5791 args.Add (new Argument (left.CreateExpressionTree (ec)));
5792 args.Add (new Argument (right.CreateExpressionTree (ec)));
5793 if (method != null) {
5795 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5797 args.Add (new Argument (method));
5800 return CreateExpressionFactoryCall (ec, method_name, args);
5803 public override object Accept (StructuralVisitor visitor)
5805 return visitor.Visit (this);
5811 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5812 // b, c, d... may be strings or objects.
5814 public class StringConcat : Expression
5816 Arguments arguments;
5818 StringConcat (Location loc)
5821 arguments = new Arguments (2);
5824 public override bool ContainsEmitWithAwait ()
5826 return arguments.ContainsEmitWithAwait ();
5829 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5831 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5832 throw new ArgumentException ();
5834 var s = new StringConcat (loc);
5835 s.type = rc.BuiltinTypes.String;
5836 s.eclass = ExprClass.Value;
5838 s.Append (rc, left);
5839 s.Append (rc, right);
5843 public override Expression CreateExpressionTree (ResolveContext ec)
5845 Argument arg = arguments [0];
5846 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5850 // Creates nested calls tree from an array of arguments used for IL emit
5852 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5854 Arguments concat_args = new Arguments (2);
5855 Arguments add_args = new Arguments (3);
5857 concat_args.Add (left);
5858 add_args.Add (new Argument (left_etree));
5860 concat_args.Add (arguments [pos]);
5861 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5863 var methods = GetConcatMethodCandidates ();
5864 if (methods == null)
5867 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5868 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5872 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5874 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5875 if (++pos == arguments.Count)
5878 left = new Argument (new EmptyExpression (method.ReturnType));
5879 return CreateExpressionAddCall (ec, left, expr, pos);
5882 protected override Expression DoResolve (ResolveContext ec)
5887 void Append (ResolveContext rc, Expression operand)
5892 StringConstant sc = operand as StringConstant;
5894 if (arguments.Count != 0) {
5895 Argument last_argument = arguments [arguments.Count - 1];
5896 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5897 if (last_expr_constant != null) {
5898 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5904 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5906 StringConcat concat_oper = operand as StringConcat;
5907 if (concat_oper != null) {
5908 arguments.AddRange (concat_oper.arguments);
5913 arguments.Add (new Argument (operand));
5916 IList<MemberSpec> GetConcatMethodCandidates ()
5918 return MemberCache.FindMembers (type, "Concat", true);
5921 public override void Emit (EmitContext ec)
5923 // Optimize by removing any extra null arguments, they are no-op
5924 for (int i = 0; i < arguments.Count; ++i) {
5925 if (arguments[i].Expr is NullConstant)
5926 arguments.RemoveAt (i--);
5929 var members = GetConcatMethodCandidates ();
5930 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5931 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5932 if (method != null) {
5933 var call = new CallEmitter ();
5934 call.EmitPredefined (ec, method, arguments, false);
5938 public override void FlowAnalysis (FlowAnalysisContext fc)
5940 arguments.FlowAnalysis (fc);
5943 public override SLE.Expression MakeExpression (BuilderContext ctx)
5945 if (arguments.Count != 2)
5946 throw new NotImplementedException ("arguments.Count != 2");
5948 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5949 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5954 // User-defined conditional logical operator
5956 public class ConditionalLogicalOperator : UserOperatorCall
5958 readonly bool is_and;
5959 Expression oper_expr;
5961 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5962 : base (oper, arguments, expr_tree, loc)
5964 this.is_and = is_and;
5965 eclass = ExprClass.Unresolved;
5968 protected override Expression DoResolve (ResolveContext ec)
5970 AParametersCollection pd = oper.Parameters;
5971 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5972 ec.Report.Error (217, loc,
5973 "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",
5974 oper.GetSignatureForError ());
5978 Expression left_dup = new EmptyExpression (type);
5979 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5980 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5981 if (op_true == null || op_false == null) {
5982 ec.Report.Error (218, loc,
5983 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5984 type.GetSignatureForError (), oper.GetSignatureForError ());
5988 oper_expr = is_and ? op_false : op_true;
5989 eclass = ExprClass.Value;
5993 public override void Emit (EmitContext ec)
5995 Label end_target = ec.DefineLabel ();
5998 // Emit and duplicate left argument
6000 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
6001 if (right_contains_await) {
6002 arguments[0] = arguments[0].EmitToField (ec, false);
6003 arguments[0].Expr.Emit (ec);
6005 arguments[0].Expr.Emit (ec);
6006 ec.Emit (OpCodes.Dup);
6007 arguments.RemoveAt (0);
6010 oper_expr.EmitBranchable (ec, end_target, true);
6014 if (right_contains_await) {
6016 // Special handling when right expression contains await and left argument
6017 // could not be left on stack before logical branch
6019 Label skip_left_load = ec.DefineLabel ();
6020 ec.Emit (OpCodes.Br_S, skip_left_load);
6021 ec.MarkLabel (end_target);
6022 arguments[0].Expr.Emit (ec);
6023 ec.MarkLabel (skip_left_load);
6025 ec.MarkLabel (end_target);
6030 public class PointerArithmetic : Expression {
6031 Expression left, right;
6032 readonly Binary.Operator op;
6035 // We assume that `l' is always a pointer
6037 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
6046 public override bool ContainsEmitWithAwait ()
6048 throw new NotImplementedException ();
6051 public override Expression CreateExpressionTree (ResolveContext ec)
6053 Error_PointerInsideExpressionTree (ec);
6057 protected override Expression DoResolve (ResolveContext ec)
6059 eclass = ExprClass.Variable;
6061 var pc = left.Type as PointerContainer;
6062 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6063 Error_VoidPointerOperation (ec);
6070 public override void Emit (EmitContext ec)
6072 TypeSpec op_type = left.Type;
6074 // It must be either array or fixed buffer
6076 if (TypeManager.HasElementType (op_type)) {
6077 element = TypeManager.GetElementType (op_type);
6079 FieldExpr fe = left as FieldExpr;
6081 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6086 int size = BuiltinTypeSpec.GetSize(element);
6087 TypeSpec rtype = right.Type;
6089 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6091 // handle (pointer - pointer)
6095 ec.Emit (OpCodes.Sub);
6099 ec.Emit (OpCodes.Sizeof, element);
6102 ec.Emit (OpCodes.Div);
6104 ec.Emit (OpCodes.Conv_I8);
6107 // handle + and - on (pointer op int)
6109 Constant left_const = left as Constant;
6110 if (left_const != null) {
6112 // Optimize ((T*)null) pointer operations
6114 if (left_const.IsDefaultValue) {
6115 left = EmptyExpression.Null;
6123 var right_const = right as Constant;
6124 if (right_const != null) {
6126 // Optimize 0-based arithmetic
6128 if (right_const.IsDefaultValue)
6132 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6134 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6136 // TODO: Should be the checks resolve context sensitive?
6137 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6138 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6144 if (right_const == null) {
6145 switch (rtype.BuiltinType) {
6146 case BuiltinTypeSpec.Type.SByte:
6147 case BuiltinTypeSpec.Type.Byte:
6148 case BuiltinTypeSpec.Type.Short:
6149 case BuiltinTypeSpec.Type.UShort:
6150 case BuiltinTypeSpec.Type.Int:
6151 ec.Emit (OpCodes.Conv_I);
6153 case BuiltinTypeSpec.Type.UInt:
6154 ec.Emit (OpCodes.Conv_U);
6159 if (right_const == null && size != 1){
6161 ec.Emit (OpCodes.Sizeof, element);
6164 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6165 ec.Emit (OpCodes.Conv_I8);
6167 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6170 if (left_const == null) {
6171 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6172 ec.Emit (OpCodes.Conv_I);
6173 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6174 ec.Emit (OpCodes.Conv_U);
6176 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6183 // A boolean-expression is an expression that yields a result
6186 public class BooleanExpression : ShimExpression
6188 public BooleanExpression (Expression expr)
6191 this.loc = expr.Location;
6194 public override Expression CreateExpressionTree (ResolveContext ec)
6196 // TODO: We should emit IsTrue (v4) instead of direct user operator
6197 // call but that would break csc compatibility
6198 return base.CreateExpressionTree (ec);
6201 protected override Expression DoResolve (ResolveContext ec)
6203 // A boolean-expression is required to be of a type
6204 // that can be implicitly converted to bool or of
6205 // a type that implements operator true
6207 expr = expr.Resolve (ec);
6211 Assign ass = expr as Assign;
6212 if (ass != null && ass.Source is Constant) {
6213 ec.Report.Warning (665, 3, loc,
6214 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6217 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6220 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6221 Arguments args = new Arguments (1);
6222 args.Add (new Argument (expr));
6223 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6226 type = ec.BuiltinTypes.Bool;
6227 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6228 if (converted != null)
6232 // If no implicit conversion to bool exists, try using `operator true'
6234 converted = GetOperatorTrue (ec, expr, loc);
6235 if (converted == null) {
6236 expr.Error_ValueCannotBeConverted (ec, type, false);
6243 public override object Accept (StructuralVisitor visitor)
6245 return visitor.Visit (this);
6249 public class BooleanExpressionFalse : Unary
6251 public BooleanExpressionFalse (Expression expr)
6252 : base (Operator.LogicalNot, expr, expr.Location)
6256 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6258 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6263 /// Implements the ternary conditional operator (?:)
6265 public class Conditional : Expression {
6266 Expression expr, true_expr, false_expr;
6268 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6271 this.true_expr = true_expr;
6272 this.false_expr = false_expr;
6278 public Expression Expr {
6284 public Expression TrueExpr {
6290 public Expression FalseExpr {
6298 public override bool ContainsEmitWithAwait ()
6300 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6303 public override Expression CreateExpressionTree (ResolveContext ec)
6305 Arguments args = new Arguments (3);
6306 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6307 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6308 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6309 return CreateExpressionFactoryCall (ec, "Condition", args);
6312 protected override Expression DoResolve (ResolveContext ec)
6314 expr = expr.Resolve (ec);
6315 true_expr = true_expr.Resolve (ec);
6316 false_expr = false_expr.Resolve (ec);
6318 if (true_expr == null || false_expr == null || expr == null)
6321 eclass = ExprClass.Value;
6322 TypeSpec true_type = true_expr.Type;
6323 TypeSpec false_type = false_expr.Type;
6327 // First, if an implicit conversion exists from true_expr
6328 // to false_expr, then the result type is of type false_expr.Type
6330 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6331 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6332 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6334 // Check if both can convert implicitly to each other's type
6338 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6339 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6341 // LAMESPEC: There seems to be hardcoded promotition to int type when
6342 // both sides are numeric constants and one side is int constant and
6343 // other side is numeric constant convertible to int.
6345 // var res = condition ? (short)1 : 1;
6347 // Type of res is int even if according to the spec the conversion is
6348 // ambiguous because 1 literal can be converted to short.
6350 if (conv_false_expr != null) {
6351 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6353 conv_false_expr = null;
6354 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6355 conv_false_expr = null;
6359 if (conv_false_expr != null) {
6360 ec.Report.Error (172, true_expr.Location,
6361 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6362 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6367 if (true_expr.Type != type)
6368 true_expr = EmptyCast.Create (true_expr, type);
6369 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6372 if (false_type != InternalType.ErrorType) {
6373 ec.Report.Error (173, true_expr.Location,
6374 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6375 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6381 Constant c = expr as Constant;
6383 bool is_false = c.IsDefaultValue;
6386 // Don't issue the warning for constant expressions
6388 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6389 // CSC: Missing warning
6390 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6393 return ReducedExpression.Create (
6394 is_false ? false_expr : true_expr, this,
6395 false_expr is Constant && true_expr is Constant).Resolve (ec);
6401 public override void Emit (EmitContext ec)
6403 Label false_target = ec.DefineLabel ();
6404 Label end_target = ec.DefineLabel ();
6406 expr.EmitBranchable (ec, false_target, false);
6407 true_expr.Emit (ec);
6410 // Verifier doesn't support interface merging. When there are two types on
6411 // the stack without common type hint and the common type is an interface.
6412 // Use temporary local to give verifier hint on what type to unify the stack
6414 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6415 var temp = ec.GetTemporaryLocal (type);
6416 ec.Emit (OpCodes.Stloc, temp);
6417 ec.Emit (OpCodes.Ldloc, temp);
6418 ec.FreeTemporaryLocal (temp, type);
6421 ec.Emit (OpCodes.Br, end_target);
6422 ec.MarkLabel (false_target);
6423 false_expr.Emit (ec);
6424 ec.MarkLabel (end_target);
6427 public override void FlowAnalysis (FlowAnalysisContext fc)
6429 expr.FlowAnalysisConditional (fc);
6430 var expr_true = fc.DefiniteAssignmentOnTrue;
6431 var expr_false = fc.DefiniteAssignmentOnFalse;
6433 fc.BranchDefiniteAssignment (expr_true);
6434 true_expr.FlowAnalysis (fc);
6435 var true_fc = fc.DefiniteAssignment;
6437 fc.BranchDefiniteAssignment (expr_false);
6438 false_expr.FlowAnalysis (fc);
6440 fc.DefiniteAssignment &= true_fc;
6443 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6445 expr.FlowAnalysisConditional (fc);
6446 var expr_true = fc.DefiniteAssignmentOnTrue;
6447 var expr_false = fc.DefiniteAssignmentOnFalse;
6449 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6450 true_expr.FlowAnalysisConditional (fc);
6451 var true_fc = fc.DefiniteAssignment;
6452 var true_da_true = fc.DefiniteAssignmentOnTrue;
6453 var true_da_false = fc.DefiniteAssignmentOnFalse;
6455 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6456 false_expr.FlowAnalysisConditional (fc);
6458 fc.DefiniteAssignment &= true_fc;
6459 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6460 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6463 protected override void CloneTo (CloneContext clonectx, Expression t)
6465 Conditional target = (Conditional) t;
6467 target.expr = expr.Clone (clonectx);
6468 target.true_expr = true_expr.Clone (clonectx);
6469 target.false_expr = false_expr.Clone (clonectx);
6473 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6475 LocalTemporary temp;
6478 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6479 public abstract void SetHasAddressTaken ();
6481 public abstract bool IsLockedByStatement { get; set; }
6483 public abstract bool IsFixed { get; }
6484 public abstract bool IsRef { get; }
6485 public abstract string Name { get; }
6488 // Variable IL data, it has to be protected to encapsulate hoisted variables
6490 protected abstract ILocalVariable Variable { get; }
6493 // Variable flow-analysis data
6495 public abstract VariableInfo VariableInfo { get; }
6498 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6500 HoistedVariable hv = GetHoistedVariable (ec);
6502 hv.AddressOf (ec, mode);
6506 Variable.EmitAddressOf (ec);
6509 public override bool ContainsEmitWithAwait ()
6514 public override Expression CreateExpressionTree (ResolveContext ec)
6516 HoistedVariable hv = GetHoistedVariable (ec);
6518 return hv.CreateExpressionTree ();
6520 Arguments arg = new Arguments (1);
6521 arg.Add (new Argument (this));
6522 return CreateExpressionFactoryCall (ec, "Constant", arg);
6525 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6527 if (IsLockedByStatement) {
6528 rc.Report.Warning (728, 2, loc,
6529 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6536 public override void Emit (EmitContext ec)
6541 public override void EmitSideEffect (EmitContext ec)
6547 // This method is used by parameters that are references, that are
6548 // being passed as references: we only want to pass the pointer (that
6549 // is already stored in the parameter, not the address of the pointer,
6550 // and not the value of the variable).
6552 public void EmitLoad (EmitContext ec)
6557 public void Emit (EmitContext ec, bool leave_copy)
6559 HoistedVariable hv = GetHoistedVariable (ec);
6561 hv.Emit (ec, leave_copy);
6569 // If we are a reference, we loaded on the stack a pointer
6570 // Now lets load the real value
6572 ec.EmitLoadFromPtr (type);
6576 ec.Emit (OpCodes.Dup);
6579 temp = new LocalTemporary (Type);
6585 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6586 bool prepare_for_load)
6588 HoistedVariable hv = GetHoistedVariable (ec);
6590 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6594 bool dereference = IsRef && !(source is ReferenceExpression);
6595 New n_source = source as New;
6596 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6597 if (!n_source.Emit (ec, this)) {
6601 ec.EmitLoadFromPtr (type);
6613 ec.Emit (OpCodes.Dup);
6615 temp = new LocalTemporary (Type);
6621 ec.EmitStoreFromPtr (type);
6623 Variable.EmitAssign (ec);
6631 public override Expression EmitToField (EmitContext ec)
6633 HoistedVariable hv = GetHoistedVariable (ec);
6635 return hv.EmitToField (ec);
6638 return base.EmitToField (ec);
6641 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6643 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6646 public HoistedVariable GetHoistedVariable (EmitContext ec)
6648 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6651 public override string GetSignatureForError ()
6656 public bool IsHoisted {
6657 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6662 // Resolved reference to a local variable
6664 public class LocalVariableReference : VariableReference
6666 public LocalVariable local_info;
6668 public LocalVariableReference (LocalVariable li, Location l)
6670 this.local_info = li;
6674 public override VariableInfo VariableInfo {
6675 get { return local_info.VariableInfo; }
6678 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6680 return local_info.HoistedVariant;
6686 // A local variable is always fixed
6688 public override bool IsFixed {
6694 public override bool IsLockedByStatement {
6696 return local_info.IsLocked;
6699 local_info.IsLocked = value;
6703 public override bool IsRef {
6704 get { return local_info.IsByRef; }
6707 public override string Name {
6708 get { return local_info.Name; }
6713 public override void FlowAnalysis (FlowAnalysisContext fc)
6715 VariableInfo variable_info = VariableInfo;
6716 if (variable_info == null)
6719 if (fc.IsDefinitelyAssigned (variable_info))
6722 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6723 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6726 public override void SetHasAddressTaken ()
6728 local_info.SetHasAddressTaken ();
6731 void DoResolveBase (ResolveContext ec)
6733 eclass = ExprClass.Variable;
6734 type = local_info.Type;
6737 // If we are referencing a variable from the external block
6738 // flag it for capturing
6740 if (ec.MustCaptureVariable (local_info)) {
6741 if (local_info.AddressTaken) {
6742 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6743 } else if (local_info.IsFixed) {
6744 ec.Report.Error (1764, loc,
6745 "Cannot use fixed variable `{0}' inside an anonymous method, lambda expression or query expression",
6746 GetSignatureForError ());
6747 } else if (local_info.IsByRef) {
6748 ec.Report.Error (8175, loc,
6749 "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression",
6750 GetSignatureForError ());
6753 if (ec.IsVariableCapturingRequired) {
6754 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6755 storey.CaptureLocalVariable (ec, local_info);
6760 protected override Expression DoResolve (ResolveContext ec)
6762 local_info.SetIsUsed ();
6766 if (local_info.Type == InternalType.VarOutType) {
6767 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6768 GetSignatureForError ());
6770 type = InternalType.ErrorType;
6776 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6779 // Don't be too pedantic when variable is used as out param or for some broken code
6780 // which uses property/indexer access to run some initialization
6782 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6783 local_info.SetIsUsed ();
6785 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6786 if (rhs == EmptyExpression.LValueMemberAccess) {
6787 // CS1654 already reported
6791 if (rhs == EmptyExpression.OutAccess) {
6792 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6793 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6794 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6795 } else if (rhs == EmptyExpression.UnaryAddress) {
6796 code = 459; msg = "Cannot take the address of {1} `{0}'";
6798 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6800 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6804 if (eclass == ExprClass.Unresolved)
6807 return base.DoResolveLValue (ec, rhs);
6810 public override int GetHashCode ()
6812 return local_info.GetHashCode ();
6815 public override bool Equals (object obj)
6817 LocalVariableReference lvr = obj as LocalVariableReference;
6821 return local_info == lvr.local_info;
6824 protected override ILocalVariable Variable {
6825 get { return local_info; }
6828 public override string ToString ()
6830 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6833 protected override void CloneTo (CloneContext clonectx, Expression t)
6840 /// This represents a reference to a parameter in the intermediate
6843 public class ParameterReference : VariableReference
6845 protected ParametersBlock.ParameterInfo pi;
6847 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6855 public override bool IsLockedByStatement {
6860 pi.IsLocked = value;
6864 public override bool IsRef {
6865 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6868 bool HasOutModifier {
6869 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6872 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6874 return pi.Parameter.HoistedVariant;
6878 // A ref or out parameter is classified as a moveable variable, even
6879 // if the argument given for the parameter is a fixed variable
6881 public override bool IsFixed {
6882 get { return !IsRef; }
6885 public override string Name {
6886 get { return Parameter.Name; }
6889 public Parameter Parameter {
6890 get { return pi.Parameter; }
6893 public override VariableInfo VariableInfo {
6894 get { return pi.VariableInfo; }
6897 protected override ILocalVariable Variable {
6898 get { return Parameter; }
6903 public override void AddressOf (EmitContext ec, AddressOp mode)
6906 // ParameterReferences might already be a reference
6913 base.AddressOf (ec, mode);
6916 public override void SetHasAddressTaken ()
6918 Parameter.HasAddressTaken = true;
6921 bool DoResolveBase (ResolveContext ec)
6923 if (eclass != ExprClass.Unresolved)
6926 type = pi.ParameterType;
6927 eclass = ExprClass.Variable;
6930 // If we are referencing a parameter from the external block
6931 // flag it for capturing
6933 if (ec.MustCaptureVariable (pi)) {
6934 if (Parameter.HasAddressTaken)
6935 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6938 ec.Report.Error (1628, loc,
6939 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6940 Name, ec.CurrentAnonymousMethod.ContainerType);
6943 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6944 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6945 storey.CaptureParameter (ec, pi, this);
6952 public override int GetHashCode ()
6954 return Name.GetHashCode ();
6957 public override bool Equals (object obj)
6959 ParameterReference pr = obj as ParameterReference;
6963 return Name == pr.Name;
6966 protected override void CloneTo (CloneContext clonectx, Expression target)
6972 public override Expression CreateExpressionTree (ResolveContext ec)
6974 HoistedVariable hv = GetHoistedVariable (ec);
6976 return hv.CreateExpressionTree ();
6978 return Parameter.ExpressionTreeVariableReference ();
6981 protected override Expression DoResolve (ResolveContext ec)
6983 if (!DoResolveBase (ec))
6989 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6991 if (!DoResolveBase (ec))
6994 if (Parameter.HoistedVariant != null)
6995 Parameter.HoistedVariant.IsAssigned = true;
6997 return base.DoResolveLValue (ec, right_side);
7000 public override void FlowAnalysis (FlowAnalysisContext fc)
7002 VariableInfo variable_info = VariableInfo;
7003 if (variable_info == null)
7006 if (fc.IsDefinitelyAssigned (variable_info))
7009 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
7010 fc.SetVariableAssigned (variable_info);
7015 /// Invocation of methods or delegates.
7017 public class Invocation : ExpressionStatement
7019 public class Predefined : Invocation
7021 public Predefined (MethodGroupExpr expr, Arguments arguments)
7022 : base (expr, arguments)
7027 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
7029 mg.BestCandidate.CheckObsoleteness (rc, loc);
7035 protected Arguments arguments;
7036 protected Expression expr;
7037 protected MethodGroupExpr mg;
7038 bool conditional_access_receiver;
7040 public Invocation (Expression expr, Arguments arguments)
7043 this.arguments = arguments;
7045 loc = expr.Location;
7050 public Arguments Arguments {
7056 public Expression Exp {
7062 public MethodGroupExpr MethodGroup {
7068 public override Location StartLocation {
7070 return expr.StartLocation;
7076 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7078 if (MethodGroup == null)
7081 var candidate = MethodGroup.BestCandidate;
7082 if (candidate == null || !(candidate.IsStatic || Exp is This))
7085 var args_count = arguments == null ? 0 : arguments.Count;
7086 if (args_count != body.Parameters.Count)
7089 var lambda_parameters = body.Block.Parameters.FixedParameters;
7090 for (int i = 0; i < args_count; ++i) {
7091 var pr = arguments[i].Expr as ParameterReference;
7095 if (lambda_parameters[i] != pr.Parameter)
7098 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7102 var emg = MethodGroup as ExtensionMethodGroupExpr;
7104 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7105 if (candidate.IsGeneric) {
7106 var targs = new TypeExpression [candidate.Arity];
7107 for (int i = 0; i < targs.Length; ++i) {
7108 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7111 mg.SetTypeArguments (null, new TypeArguments (targs));
7120 protected override void CloneTo (CloneContext clonectx, Expression t)
7122 Invocation target = (Invocation) t;
7124 if (arguments != null)
7125 target.arguments = arguments.Clone (clonectx);
7127 target.expr = expr.Clone (clonectx);
7130 public override bool ContainsEmitWithAwait ()
7132 if (arguments != null && arguments.ContainsEmitWithAwait ())
7135 return mg.ContainsEmitWithAwait ();
7138 public override Expression CreateExpressionTree (ResolveContext ec)
7140 Expression instance = mg.IsInstance ?
7141 mg.InstanceExpression.CreateExpressionTree (ec) :
7142 new NullLiteral (loc);
7144 var args = Arguments.CreateForExpressionTree (ec, arguments,
7146 mg.CreateExpressionTree (ec));
7148 return CreateExpressionFactoryCall (ec, "Call", args);
7151 void ResolveConditionalAccessReceiver (ResolveContext rc)
7153 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7154 conditional_access_receiver = true;
7158 bool statement_resolve;
7159 public override ExpressionStatement ResolveStatement (BlockContext bc)
7161 statement_resolve = true;
7162 var es = base.ResolveStatement (bc);
7163 statement_resolve = false;
7168 protected override Expression DoResolve (ResolveContext rc)
7170 ResolveConditionalAccessReceiver (rc);
7171 return DoResolveInvocation (rc, null);
7174 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7176 var sn = expr as SimpleName;
7177 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
7178 var targets = new List<Expression> (arguments.Count);
7179 var variables = new List<LocalVariable> (arguments.Count);
7180 foreach (var arg in arguments) {
7181 var arg_sn = arg.Expr as SimpleName;
7182 if (arg_sn == null || arg_sn.Arity != 0) {
7183 rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
7184 return ErrorExpression.Instance;
7187 var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
7188 rc.CurrentBlock.AddLocalName (lv);
7191 targets.Add (new LocalVariableReference (lv, arg_sn.Location));
7194 var res = new TupleDeconstruct (targets, variables, right_side, loc);
7195 return res.Resolve (rc);
7198 if (right_side != null) {
7199 if (eclass != ExprClass.Unresolved)
7202 var res = DoResolveInvocation (rc, right_side);
7209 return base.DoResolveLValue (rc, right_side);
7212 Expression DoResolveInvocation (ResolveContext ec, Expression rhs)
7214 Expression member_expr;
7215 var atn = expr as ATypeNameExpression;
7217 var flags = default (ResolveContext.FlagsHandle);
7218 if (conditional_access_receiver)
7219 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7222 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7223 if (member_expr != null) {
7224 var name_of = member_expr as NameOf;
7225 if (name_of != null) {
7226 return name_of.ResolveOverload (ec, arguments);
7229 member_expr = member_expr.Resolve (ec);
7232 member_expr = expr.Resolve (ec);
7235 if (conditional_access_receiver)
7238 if (member_expr == null)
7242 // Next, evaluate all the expressions in the argument list
7244 bool dynamic_arg = false;
7245 if (arguments != null) {
7246 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7247 arguments.Resolve (ec, out dynamic_arg);
7251 TypeSpec expr_type = member_expr.Type;
7252 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7253 return DoResolveDynamic (ec, member_expr);
7255 mg = member_expr as MethodGroupExpr;
7256 Expression invoke = null;
7259 if (expr_type != null && expr_type.IsDelegate) {
7260 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7261 invoke = invoke.Resolve (ec);
7262 if (invoke == null || !dynamic_arg)
7265 if (member_expr is RuntimeValueExpression) {
7266 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7267 member_expr.Type.GetSignatureForError ());
7271 MemberExpr me = member_expr as MemberExpr;
7273 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7277 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7278 member_expr.GetSignatureForError ());
7283 if (invoke == null) {
7284 mg = DoResolveOverload (ec);
7290 return DoResolveDynamic (ec, member_expr);
7292 var method = mg.BestCandidate;
7293 type = mg.BestCandidateReturnType;
7294 if (conditional_access_receiver && !statement_resolve)
7295 type = LiftMemberType (ec, type);
7297 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7299 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7301 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7305 IsSpecialMethodInvocation (ec, method, loc);
7307 eclass = ExprClass.Value;
7309 if (type.Kind == MemberKind.ByRef) {
7310 if (rhs == null && arguments?.ContainsEmitWithAwait () == true) {
7311 ec.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
7312 GetSignatureForError ());
7315 if (rhs != EmptyExpression.OutAccess)
7316 return ByRefDereference.Create (this).Resolve (ec);
7322 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7325 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7327 args = dmb.Arguments;
7328 if (arguments != null)
7329 args.AddRange (arguments);
7330 } else if (mg == null) {
7331 if (arguments == null)
7332 args = new Arguments (1);
7336 args.Insert (0, new Argument (memberExpr));
7340 ec.Report.Error (1971, loc,
7341 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7346 if (arguments == null)
7347 args = new Arguments (1);
7351 MemberAccess ma = expr as MemberAccess;
7353 var inst = mg.InstanceExpression;
7354 var left_type = inst as TypeExpr;
7355 if (left_type != null) {
7356 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7357 } else if (inst != null) {
7359 // Any value type has to be pass as by-ref to get back the same
7360 // instance on which the member was called
7362 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7363 Argument.AType.Ref : Argument.AType.None;
7364 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7366 } else { // is SimpleName
7367 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7368 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7370 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7375 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7378 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7380 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7383 public override void FlowAnalysis (FlowAnalysisContext fc)
7385 if (mg.IsConditionallyExcluded)
7388 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7390 mg.FlowAnalysis (fc);
7392 if (arguments != null)
7393 arguments.FlowAnalysis (fc);
7395 if (conditional_access_receiver)
7396 fc.DefiniteAssignment = da;
7399 public override string GetSignatureForError ()
7401 return mg.GetSignatureForError ();
7404 public override bool HasConditionalAccess ()
7406 return expr.HasConditionalAccess ();
7410 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7411 // or the type dynamic, then the member is invocable
7413 public static bool IsMemberInvocable (MemberSpec member)
7415 switch (member.Kind) {
7416 case MemberKind.Event:
7418 case MemberKind.Field:
7419 case MemberKind.Property:
7420 var m = member as IInterfaceMemberSpec;
7421 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7427 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7429 if (!method.IsReservedMethod)
7432 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7435 ec.Report.SymbolRelatedToPreviousError (method);
7436 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7437 method.GetSignatureForError ());
7442 public override void Emit (EmitContext ec)
7444 if (mg.IsConditionallyExcluded)
7447 if (conditional_access_receiver)
7448 mg.EmitCall (ec, arguments, type, false);
7450 mg.EmitCall (ec, arguments, false);
7453 public override void EmitPrepare (EmitContext ec)
7455 mg.EmitPrepare (ec);
7457 arguments?.EmitPrepare (ec);
7460 public override void EmitStatement (EmitContext ec)
7462 if (mg.IsConditionallyExcluded)
7465 if (conditional_access_receiver)
7466 mg.EmitCall (ec, arguments, type, true);
7468 mg.EmitCall (ec, arguments, true);
7471 public override SLE.Expression MakeExpression (BuilderContext ctx)
7473 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7476 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7479 throw new NotSupportedException ();
7481 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7482 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7486 public override object Accept (StructuralVisitor visitor)
7488 return visitor.Visit (this);
7493 // Implements simple new expression
7495 public class New : ExpressionStatement, IMemoryLocation
7497 protected Arguments arguments;
7500 // During bootstrap, it contains the RequestedType,
7501 // but if `type' is not null, it *might* contain a NewDelegate
7502 // (because of field multi-initialization)
7504 protected Expression RequestedType;
7506 protected MethodSpec method;
7508 public New (Expression requested_type, Arguments arguments, Location l)
7510 RequestedType = requested_type;
7511 this.arguments = arguments;
7516 public Arguments Arguments {
7523 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7525 public bool IsGeneratedStructConstructor {
7527 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7531 public Expression TypeExpression {
7533 return RequestedType;
7540 /// Converts complex core type syntax like 'new int ()' to simple constant
7542 public static Constant Constantify (TypeSpec t, Location loc)
7544 switch (t.BuiltinType) {
7545 case BuiltinTypeSpec.Type.Int:
7546 return new IntConstant (t, 0, loc);
7547 case BuiltinTypeSpec.Type.UInt:
7548 return new UIntConstant (t, 0, loc);
7549 case BuiltinTypeSpec.Type.Long:
7550 return new LongConstant (t, 0, loc);
7551 case BuiltinTypeSpec.Type.ULong:
7552 return new ULongConstant (t, 0, loc);
7553 case BuiltinTypeSpec.Type.Float:
7554 return new FloatConstant (t, 0, loc);
7555 case BuiltinTypeSpec.Type.Double:
7556 return new DoubleConstant (t, 0, loc);
7557 case BuiltinTypeSpec.Type.Short:
7558 return new ShortConstant (t, 0, loc);
7559 case BuiltinTypeSpec.Type.UShort:
7560 return new UShortConstant (t, 0, loc);
7561 case BuiltinTypeSpec.Type.SByte:
7562 return new SByteConstant (t, 0, loc);
7563 case BuiltinTypeSpec.Type.Byte:
7564 return new ByteConstant (t, 0, loc);
7565 case BuiltinTypeSpec.Type.Char:
7566 return new CharConstant (t, '\0', loc);
7567 case BuiltinTypeSpec.Type.Bool:
7568 return new BoolConstant (t, false, loc);
7569 case BuiltinTypeSpec.Type.Decimal:
7570 return new DecimalConstant (t, 0, loc);
7574 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7576 if (t.IsNullableType)
7577 return Nullable.LiftedNull.Create (t, loc);
7582 public override bool ContainsEmitWithAwait ()
7584 return arguments != null && arguments.ContainsEmitWithAwait ();
7588 // Checks whether the type is an interface that has the
7589 // [ComImport, CoClass] attributes and must be treated
7592 public Expression CheckComImport (ResolveContext ec)
7594 if (!type.IsInterface)
7598 // Turn the call into:
7599 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7601 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7602 if (real_class == null)
7605 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7606 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7607 return cast.Resolve (ec);
7610 public override Expression CreateExpressionTree (ResolveContext ec)
7613 if (method == null) {
7614 args = new Arguments (1);
7615 args.Add (new Argument (new TypeOf (type, loc)));
7617 args = Arguments.CreateForExpressionTree (ec,
7618 arguments, new TypeOfMethod (method, loc));
7621 return CreateExpressionFactoryCall (ec, "New", args);
7624 protected override Expression DoResolve (ResolveContext ec)
7626 if (RequestedType is TupleTypeExpr) {
7627 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
7630 type = RequestedType.ResolveAsType (ec);
7634 eclass = ExprClass.Value;
7636 if (type.IsPointer) {
7637 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7638 type.GetSignatureForError ());
7642 if (arguments == null) {
7643 Constant c = Constantify (type, RequestedType.Location);
7645 return ReducedExpression.Create (c, this);
7648 if (type.IsDelegate) {
7649 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7652 var tparam = type as TypeParameterSpec;
7653 if (tparam != null) {
7655 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7656 // where type parameter constraint is inflated to struct
7658 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7659 ec.Report.Error (304, loc,
7660 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7661 type.GetSignatureForError ());
7664 if ((arguments != null) && (arguments.Count != 0)) {
7665 ec.Report.Error (417, loc,
7666 "`{0}': cannot provide arguments when creating an instance of a variable type",
7667 type.GetSignatureForError ());
7673 if (type.IsStatic) {
7674 ec.Report.SymbolRelatedToPreviousError (type);
7675 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7679 if (type.IsInterface || type.IsAbstract){
7680 if (!TypeManager.IsGenericType (type)) {
7681 RequestedType = CheckComImport (ec);
7682 if (RequestedType != null)
7683 return RequestedType;
7686 ec.Report.SymbolRelatedToPreviousError (type);
7687 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7692 if (arguments != null) {
7693 arguments.Resolve (ec, out dynamic);
7698 method = ConstructorLookup (ec, type, ref arguments, loc);
7701 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7702 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7708 void DoEmitTypeParameter (EmitContext ec)
7710 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7714 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7715 ec.Emit (OpCodes.Call, ctor_factory);
7719 // This Emit can be invoked in two contexts:
7720 // * As a mechanism that will leave a value on the stack (new object)
7721 // * As one that wont (init struct)
7723 // If we are dealing with a ValueType, we have a few
7724 // situations to deal with:
7726 // * The target is a ValueType, and we have been provided
7727 // the instance (this is easy, we are being assigned).
7729 // * The target of New is being passed as an argument,
7730 // to a boxing operation or a function that takes a
7733 // In this case, we need to create a temporary variable
7734 // that is the argument of New.
7736 // Returns whether a value is left on the stack
7738 // *** Implementation note ***
7740 // To benefit from this optimization, each assignable expression
7741 // has to manually cast to New and call this Emit.
7743 // TODO: It's worth to implement it for arrays and fields
7745 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7747 bool is_value_type = type.IsStructOrEnum;
7748 VariableReference vr = target as VariableReference;
7750 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7752 if (target != null && is_value_type && (vr != null || method == null)) {
7753 if (prepare_await) {
7754 arguments = arguments.Emit (ec, false, true);
7755 prepare_await = false;
7758 target.AddressOf (ec, AddressOp.Store);
7759 } else if (vr != null && vr.IsRef) {
7763 if (arguments != null) {
7765 arguments = arguments.Emit (ec, false, true);
7767 arguments.Emit (ec);
7770 if (is_value_type) {
7771 if (method == null) {
7772 ec.Emit (OpCodes.Initobj, type);
7777 ec.MarkCallEntry (loc);
7778 ec.Emit (OpCodes.Call, method);
7783 if (type is TypeParameterSpec) {
7784 DoEmitTypeParameter (ec);
7788 ec.MarkCallEntry (loc);
7789 ec.Emit (OpCodes.Newobj, method);
7793 public override void Emit (EmitContext ec)
7795 LocalTemporary v = null;
7796 if (method == null && type.IsStructOrEnum) {
7797 // TODO: Use temporary variable from pool
7798 v = new LocalTemporary (type);
7805 public override void EmitStatement (EmitContext ec)
7807 LocalTemporary v = null;
7808 if (method == null && TypeSpec.IsValueType (type)) {
7809 // TODO: Use temporary variable from pool
7810 v = new LocalTemporary (type);
7814 ec.Emit (OpCodes.Pop);
7817 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7822 public override void FlowAnalysis (FlowAnalysisContext fc)
7824 if (arguments != null)
7825 arguments.FlowAnalysis (fc);
7828 public void AddressOf (EmitContext ec, AddressOp mode)
7830 EmitAddressOf (ec, mode);
7833 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7835 LocalTemporary value_target = new LocalTemporary (type);
7837 if (type is TypeParameterSpec) {
7838 DoEmitTypeParameter (ec);
7839 value_target.Store (ec);
7840 value_target.AddressOf (ec, mode);
7841 return value_target;
7844 value_target.AddressOf (ec, AddressOp.Store);
7846 if (method == null) {
7847 ec.Emit (OpCodes.Initobj, type);
7849 if (arguments != null)
7850 arguments.Emit (ec);
7852 ec.Emit (OpCodes.Call, method);
7855 value_target.AddressOf (ec, mode);
7856 return value_target;
7859 protected override void CloneTo (CloneContext clonectx, Expression t)
7861 New target = (New) t;
7863 target.RequestedType = RequestedType.Clone (clonectx);
7864 if (arguments != null){
7865 target.arguments = arguments.Clone (clonectx);
7869 public override SLE.Expression MakeExpression (BuilderContext ctx)
7872 return base.MakeExpression (ctx);
7874 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7878 public override object Accept (StructuralVisitor visitor)
7880 return visitor.Visit (this);
7885 // Array initializer expression, the expression is allowed in
7886 // variable or field initialization only which makes it tricky as
7887 // the type has to be infered based on the context either from field
7888 // type or variable type (think of multiple declarators)
7890 public class ArrayInitializer : Expression
7892 List<Expression> elements;
7893 BlockVariable variable;
7895 public ArrayInitializer (List<Expression> init, Location loc)
7901 public ArrayInitializer (int count, Location loc)
7902 : this (new List<Expression> (count), loc)
7906 public ArrayInitializer (Location loc)
7914 get { return elements.Count; }
7917 public List<Expression> Elements {
7923 public Expression this [int index] {
7925 return elements [index];
7929 public BlockVariable VariableDeclaration {
7940 public void Add (Expression expr)
7942 elements.Add (expr);
7945 public override bool ContainsEmitWithAwait ()
7947 throw new NotSupportedException ();
7950 public override Expression CreateExpressionTree (ResolveContext ec)
7952 throw new NotSupportedException ("ET");
7955 protected override void CloneTo (CloneContext clonectx, Expression t)
7957 var target = (ArrayInitializer) t;
7959 target.elements = new List<Expression> (elements.Count);
7960 foreach (var element in elements)
7961 target.elements.Add (element.Clone (clonectx));
7964 protected override Expression DoResolve (ResolveContext rc)
7966 var current_field = rc.CurrentMemberDefinition as FieldBase;
7967 TypeExpression type;
7968 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7969 type = new TypeExpression (current_field.MemberType, current_field.Location);
7970 } else if (variable != null) {
7971 if (variable.TypeExpression is VarExpr) {
7972 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7973 return EmptyExpression.Null;
7976 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7978 throw new NotImplementedException ("Unexpected array initializer context");
7981 return new ArrayCreation (type, this).Resolve (rc);
7984 public override void Emit (EmitContext ec)
7986 throw new InternalErrorException ("Missing Resolve call");
7989 public override void FlowAnalysis (FlowAnalysisContext fc)
7991 throw new InternalErrorException ("Missing Resolve call");
7994 public override object Accept (StructuralVisitor visitor)
7996 return visitor.Visit (this);
8001 /// 14.5.10.2: Represents an array creation expression.
8005 /// There are two possible scenarios here: one is an array creation
8006 /// expression that specifies the dimensions and optionally the
8007 /// initialization data and the other which does not need dimensions
8008 /// specified but where initialization data is mandatory.
8010 public class ArrayCreation : Expression
8012 FullNamedExpression requested_base_type;
8013 ArrayInitializer initializers;
8016 // The list of Argument types.
8017 // This is used to construct the `newarray' or constructor signature
8019 protected List<Expression> arguments;
8021 protected TypeSpec array_element_type;
8023 protected int dimensions;
8024 protected readonly ComposedTypeSpecifier rank;
8025 Expression first_emit;
8026 LocalTemporary first_emit_temp;
8028 protected List<Expression> array_data;
8030 Dictionary<int, int> bounds;
8033 // The number of constants in array initializers
8034 int const_initializers_count;
8035 bool only_constant_initializers;
8037 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
8038 : this (requested_base_type, rank, initializers, l)
8040 arguments = new List<Expression> (exprs);
8041 num_arguments = arguments.Count;
8045 // For expressions like int[] foo = new int[] { 1, 2, 3 };
8047 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8049 this.requested_base_type = requested_base_type;
8051 this.initializers = initializers;
8055 num_arguments = rank.Dimension;
8059 // For compiler generated single dimensional arrays only
8061 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
8062 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
8067 // For expressions like int[] foo = { 1, 2, 3 };
8069 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
8070 : this (requested_base_type, null, initializers, initializers.Location)
8074 public bool NoEmptyInterpolation { get; set; }
8076 public ComposedTypeSpecifier Rank {
8082 public FullNamedExpression TypeExpression {
8084 return this.requested_base_type;
8088 public ArrayInitializer Initializers {
8090 return this.initializers;
8094 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
8096 if (initializers != null && bounds == null) {
8098 // We use this to store all the data values in the order in which we
8099 // will need to store them in the byte blob later
8101 array_data = new List<Expression> (probe.Count);
8102 bounds = new Dictionary<int, int> ();
8105 if (specified_dims) {
8106 Expression a = arguments [idx];
8111 a = ConvertExpressionToArrayIndex (ec, a);
8117 if (initializers != null) {
8118 Constant c = a as Constant;
8119 if (c == null && a is ArrayIndexCast)
8120 c = ((ArrayIndexCast) a).Child as Constant;
8123 ec.Report.Error (150, a.Location, "A constant value is expected");
8129 value = System.Convert.ToInt32 (c.GetValue ());
8131 ec.Report.Error (150, a.Location, "A constant value is expected");
8135 // TODO: probe.Count does not fit ulong in
8136 if (value != probe.Count) {
8137 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8141 bounds[idx] = value;
8145 if (initializers == null)
8148 for (int i = 0; i < probe.Count; ++i) {
8150 if (o is ArrayInitializer) {
8151 var sub_probe = o as ArrayInitializer;
8152 if (idx + 1 >= dimensions){
8153 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8157 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8158 if (!bounds.ContainsKey(idx + 1))
8159 bounds[idx + 1] = sub_probe.Count;
8161 if (bounds[idx + 1] != sub_probe.Count) {
8162 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8166 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8169 } else if (child_bounds > 1) {
8170 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8172 Expression element = ResolveArrayElement (ec, o);
8173 if (element == null)
8176 // Initializers with the default values can be ignored
8177 Constant c = element as Constant;
8179 if (!c.IsDefaultInitializer (array_element_type)) {
8180 ++const_initializers_count;
8183 only_constant_initializers = false;
8186 array_data.Add (element);
8193 public override bool ContainsEmitWithAwait ()
8195 foreach (var arg in arguments) {
8196 if (arg.ContainsEmitWithAwait ())
8200 return InitializersContainAwait ();
8203 public override Expression CreateExpressionTree (ResolveContext ec)
8207 if (array_data == null) {
8208 args = new Arguments (arguments.Count + 1);
8209 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8210 foreach (Expression a in arguments)
8211 args.Add (new Argument (a.CreateExpressionTree (ec)));
8213 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8216 if (dimensions > 1) {
8217 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8221 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8222 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8223 if (array_data != null) {
8224 for (int i = 0; i < array_data.Count; ++i) {
8225 Expression e = array_data [i];
8226 args.Add (new Argument (e.CreateExpressionTree (ec)));
8230 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8233 void UpdateIndices (ResolveContext rc)
8236 for (var probe = initializers; probe != null;) {
8237 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8239 bounds[i++] = probe.Count;
8241 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8242 probe = (ArrayInitializer) probe[0];
8243 } else if (dimensions > i) {
8251 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8253 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8256 public override void FlowAnalysis (FlowAnalysisContext fc)
8258 foreach (var arg in arguments)
8259 arg.FlowAnalysis (fc);
8261 if (array_data != null) {
8262 foreach (var ad in array_data)
8263 ad.FlowAnalysis (fc);
8267 bool InitializersContainAwait ()
8269 if (array_data == null)
8272 foreach (var expr in array_data) {
8273 if (expr.ContainsEmitWithAwait ())
8280 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8282 element = element.Resolve (ec);
8283 if (element == null)
8286 var te = element as CompoundAssign.TargetExpression;
8288 for (int i = 1; i < initializers.Count; ++i) {
8289 if (initializers [i].ContainsEmitWithAwait ()) {
8290 te.RequiresEmitWithAwait = true;
8295 if (!te.RequiresEmitWithAwait) {
8296 if (first_emit != null)
8297 throw new InternalErrorException ("Can only handle one mutator at a time");
8298 first_emit = element;
8299 element = first_emit_temp = new LocalTemporary (element.Type);
8303 return Convert.ImplicitConversionRequired (
8304 ec, element, array_element_type, loc);
8307 protected bool ResolveInitializers (ResolveContext ec)
8310 only_constant_initializers = true;
8313 if (arguments != null) {
8315 for (int i = 0; i < arguments.Count; ++i) {
8316 res &= CheckIndices (ec, initializers, i, true, dimensions);
8317 if (initializers != null)
8324 arguments = new List<Expression> ();
8326 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8335 // Resolved the type of the array
8337 bool ResolveArrayType (ResolveContext ec)
8342 FullNamedExpression array_type_expr;
8343 if (num_arguments > 0) {
8344 array_type_expr = new ComposedCast (requested_base_type, rank);
8346 array_type_expr = requested_base_type;
8349 type = array_type_expr.ResolveAsType (ec);
8350 if (array_type_expr == null)
8353 var ac = type as ArrayContainer;
8355 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8359 array_element_type = ac.Element;
8360 dimensions = ac.Rank;
8365 protected override Expression DoResolve (ResolveContext ec)
8370 if (!ResolveArrayType (ec))
8374 // validate the initializers and fill in any missing bits
8376 if (!ResolveInitializers (ec))
8379 eclass = ExprClass.Value;
8383 byte [] MakeByteBlob ()
8388 int count = array_data.Count;
8390 TypeSpec element_type = array_element_type;
8391 if (element_type.IsEnum)
8392 element_type = EnumSpec.GetUnderlyingType (element_type);
8394 factor = BuiltinTypeSpec.GetSize (element_type);
8396 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8398 data = new byte [(count * factor + 3) & ~3];
8401 for (int i = 0; i < count; ++i) {
8402 var c = array_data[i] as Constant;
8408 object v = c.GetValue ();
8410 switch (element_type.BuiltinType) {
8411 case BuiltinTypeSpec.Type.Long:
8412 long lval = (long) v;
8414 for (int j = 0; j < factor; ++j) {
8415 data[idx + j] = (byte) (lval & 0xFF);
8419 case BuiltinTypeSpec.Type.ULong:
8420 ulong ulval = (ulong) v;
8422 for (int j = 0; j < factor; ++j) {
8423 data[idx + j] = (byte) (ulval & 0xFF);
8424 ulval = (ulval >> 8);
8427 case BuiltinTypeSpec.Type.Float:
8428 var fval = SingleConverter.SingleToInt32Bits((float) v);
8430 data[idx] = (byte) (fval & 0xff);
8431 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8432 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8433 data[idx + 3] = (byte) (fval >> 24);
8435 case BuiltinTypeSpec.Type.Double:
8436 element = BitConverter.GetBytes ((double) v);
8438 for (int j = 0; j < factor; ++j)
8439 data[idx + j] = element[j];
8441 // FIXME: Handle the ARM float format.
8442 if (!BitConverter.IsLittleEndian)
8443 System.Array.Reverse (data, idx, 8);
8445 case BuiltinTypeSpec.Type.Char:
8446 int chval = (int) ((char) v);
8448 data[idx] = (byte) (chval & 0xff);
8449 data[idx + 1] = (byte) (chval >> 8);
8451 case BuiltinTypeSpec.Type.Short:
8452 int sval = (int) ((short) v);
8454 data[idx] = (byte) (sval & 0xff);
8455 data[idx + 1] = (byte) (sval >> 8);
8457 case BuiltinTypeSpec.Type.UShort:
8458 int usval = (int) ((ushort) v);
8460 data[idx] = (byte) (usval & 0xff);
8461 data[idx + 1] = (byte) (usval >> 8);
8463 case BuiltinTypeSpec.Type.Int:
8466 data[idx] = (byte) (val & 0xff);
8467 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8468 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8469 data[idx + 3] = (byte) (val >> 24);
8471 case BuiltinTypeSpec.Type.UInt:
8472 uint uval = (uint) v;
8474 data[idx] = (byte) (uval & 0xff);
8475 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8476 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8477 data[idx + 3] = (byte) (uval >> 24);
8479 case BuiltinTypeSpec.Type.SByte:
8480 data[idx] = (byte) (sbyte) v;
8482 case BuiltinTypeSpec.Type.Byte:
8483 data[idx] = (byte) v;
8485 case BuiltinTypeSpec.Type.Bool:
8486 data[idx] = (byte) ((bool) v ? 1 : 0);
8488 case BuiltinTypeSpec.Type.Decimal:
8489 int[] bits = Decimal.GetBits ((decimal) v);
8492 // FIXME: For some reason, this doesn't work on the MS runtime.
8493 int[] nbits = new int[4];
8499 for (int j = 0; j < 4; j++) {
8500 data[p++] = (byte) (nbits[j] & 0xff);
8501 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8502 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8503 data[p++] = (byte) (nbits[j] >> 24);
8507 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8516 public override SLE.Expression MakeExpression (BuilderContext ctx)
8519 return base.MakeExpression (ctx);
8521 var initializers = new SLE.Expression [array_data.Count];
8522 for (var i = 0; i < initializers.Length; i++) {
8523 if (array_data [i] == null)
8524 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8526 initializers [i] = array_data [i].MakeExpression (ctx);
8529 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8534 // Emits the initializers for the array
8536 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8538 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8543 // First, the static data
8545 byte [] data = MakeByteBlob ();
8546 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8548 if (stackArray == null) {
8549 ec.Emit (OpCodes.Dup);
8551 stackArray.Emit (ec);
8554 ec.Emit (OpCodes.Ldtoken, fb);
8555 ec.Emit (OpCodes.Call, m);
8560 // Emits pieces of the array that can not be computed at compile
8561 // time (variables and string locations).
8563 // This always expect the top value on the stack to be the array
8565 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8567 int dims = bounds.Count;
8568 var current_pos = new int [dims];
8570 for (int i = 0; i < array_data.Count; i++){
8572 Expression e = array_data [i];
8573 var c = e as Constant;
8575 // Constant can be initialized via StaticInitializer
8576 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8580 if (stackArray != null) {
8581 if (e.ContainsEmitWithAwait ()) {
8582 e = e.EmitToField (ec);
8585 stackArray.EmitLoad (ec);
8587 ec.Emit (OpCodes.Dup);
8590 for (int idx = 0; idx < dims; idx++)
8591 ec.EmitInt (current_pos [idx]);
8594 // If we are dealing with a struct, get the
8595 // address of it, so we can store it.
8597 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8598 ec.Emit (OpCodes.Ldelema, etype);
8602 ec.EmitArrayStore ((ArrayContainer) type);
8608 for (int j = dims - 1; j >= 0; j--){
8610 if (current_pos [j] < bounds [j])
8612 current_pos [j] = 0;
8616 if (stackArray != null)
8617 stackArray.PrepareCleanup (ec);
8620 public override void Emit (EmitContext ec)
8622 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8625 var await_field = EmitToFieldSource (ec);
8626 if (await_field != null)
8627 await_field.Emit (ec);
8630 bool EmitOptimizedEmpty (EmitContext ec)
8632 if (arguments.Count != 1 || dimensions != 1)
8635 var c = arguments [0] as Constant;
8636 if (c == null || !c.IsZeroInteger)
8639 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8640 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8643 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8644 ec.Emit (OpCodes.Call, m);
8648 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8650 if (first_emit != null) {
8651 first_emit.Emit (ec);
8652 first_emit_temp.Store (ec);
8655 StackFieldExpr await_stack_field;
8656 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8657 await_stack_field = ec.GetTemporaryField (type);
8660 await_stack_field = null;
8663 EmitExpressionsList (ec, arguments);
8665 ec.EmitArrayNew ((ArrayContainer) type);
8667 if (initializers == null)
8668 return await_stack_field;
8670 if (await_stack_field != null)
8671 await_stack_field.EmitAssignFromStack (ec);
8675 // Emit static initializer for arrays which contain more than 2 items and
8676 // the static initializer will initialize at least 25% of array values or there
8677 // is more than 10 items to be initialized
8679 // NOTE: const_initializers_count does not contain default constant values.
8681 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8682 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8683 EmitStaticInitializers (ec, await_stack_field);
8685 if (!only_constant_initializers)
8686 EmitDynamicInitializers (ec, false, await_stack_field);
8690 EmitDynamicInitializers (ec, true, await_stack_field);
8693 if (first_emit_temp != null)
8694 first_emit_temp.Release (ec);
8696 return await_stack_field;
8699 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8701 // no multi dimensional or jagged arrays
8702 if (arguments.Count != 1 || array_element_type.IsArray) {
8703 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8707 // No array covariance, except for array -> object
8708 if (type != targetType) {
8709 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8710 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8714 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8715 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8720 // Single dimensional array of 0 size
8721 if (array_data == null) {
8722 IntConstant ic = arguments[0] as IntConstant;
8723 if (ic == null || !ic.IsDefaultValue) {
8724 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8732 enc.Encode (array_data.Count);
8733 foreach (var element in array_data) {
8734 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8738 protected override void CloneTo (CloneContext clonectx, Expression t)
8740 ArrayCreation target = (ArrayCreation) t;
8742 if (requested_base_type != null)
8743 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8745 if (arguments != null){
8746 target.arguments = new List<Expression> (arguments.Count);
8747 foreach (Expression e in arguments)
8748 target.arguments.Add (e.Clone (clonectx));
8751 if (initializers != null)
8752 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8755 public override object Accept (StructuralVisitor visitor)
8757 return visitor.Visit (this);
8762 // Represents an implicitly typed array epxression
8764 class ImplicitlyTypedArrayCreation : ArrayCreation
8766 TypeInferenceContext best_type_inference;
8768 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8769 : base (null, rank, initializers, loc)
8773 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8774 : base (null, initializers, loc)
8778 protected override Expression DoResolve (ResolveContext ec)
8783 dimensions = rank.Dimension;
8785 best_type_inference = new TypeInferenceContext ();
8787 if (!ResolveInitializers (ec))
8790 best_type_inference.FixAllTypes (ec);
8791 array_element_type = best_type_inference.InferredTypeArguments[0];
8792 best_type_inference = null;
8794 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
8795 ec.Report.Error (826, loc,
8796 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8801 // At this point we found common base type for all initializer elements
8802 // but we have to be sure that all static initializer elements are of
8805 UnifyInitializerElement (ec);
8807 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8808 eclass = ExprClass.Value;
8813 // Converts static initializer only
8815 void UnifyInitializerElement (ResolveContext ec)
8817 for (int i = 0; i < array_data.Count; ++i) {
8818 Expression e = array_data[i];
8820 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8824 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8826 element = element.Resolve (ec);
8827 if (element != null)
8828 best_type_inference.AddCommonTypeBound (element.Type);
8834 sealed class CompilerGeneratedThis : This
8836 public CompilerGeneratedThis (TypeSpec type, Location loc)
8842 protected override Expression DoResolve (ResolveContext rc)
8844 eclass = ExprClass.Variable;
8846 var block = rc.CurrentBlock;
8847 if (block != null) {
8848 var top = block.ParametersBlock.TopBlock;
8849 if (top.ThisVariable != null)
8850 variable_info = top.ThisVariable.VariableInfo;
8857 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8859 return DoResolve (rc);
8862 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8869 /// Represents the `this' construct
8872 public class This : VariableReference
8874 sealed class ThisVariable : ILocalVariable
8876 public static readonly ILocalVariable Instance = new ThisVariable ();
8878 public void Emit (EmitContext ec)
8883 public void EmitAssign (EmitContext ec)
8885 throw new InvalidOperationException ();
8888 public void EmitAddressOf (EmitContext ec)
8894 protected VariableInfo variable_info;
8896 public This (Location loc)
8903 public override string Name {
8904 get { return "this"; }
8907 public override bool IsLockedByStatement {
8915 public override bool IsRef {
8916 get { return type.IsStruct; }
8919 public override bool IsSideEffectFree {
8925 protected override ILocalVariable Variable {
8926 get { return ThisVariable.Instance; }
8929 public override VariableInfo VariableInfo {
8930 get { return variable_info; }
8933 public override bool IsFixed {
8934 get { return false; }
8939 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8942 // It's null for all cases when we don't need to check `this'
8943 // definitive assignment
8945 if (variable_info == null)
8948 if (fc.IsDefinitelyAssigned (variable_info))
8951 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8954 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8956 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8957 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8958 } else if (ec.CurrentAnonymousMethod != null) {
8959 ec.Report.Error (1673, loc,
8960 "Anonymous methods inside structs cannot access instance members of `this'. " +
8961 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8963 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8967 public override void FlowAnalysis (FlowAnalysisContext fc)
8969 CheckStructThisDefiniteAssignment (fc);
8972 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8977 AnonymousMethodStorey storey = ae.Storey;
8978 return storey != null ? storey.HoistedThis : null;
8981 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8983 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8986 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8989 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8995 public virtual void ResolveBase (ResolveContext ec)
8997 eclass = ExprClass.Variable;
8998 type = ec.CurrentType;
9000 if (!IsThisAvailable (ec, false)) {
9001 Error_ThisNotAvailable (ec);
9005 var block = ec.CurrentBlock;
9006 if (block != null) {
9007 var top = block.ParametersBlock.TopBlock;
9008 if (top.ThisVariable != null)
9009 variable_info = top.ThisVariable.VariableInfo;
9011 AnonymousExpression am = ec.CurrentAnonymousMethod;
9012 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
9014 // Hoisted this is almost like hoisted variable but not exactly. When
9015 // there is no variable hoisted we can simply emit an instance method
9016 // without lifting this into a storey. Unfotunatelly this complicates
9017 // things in other cases because we don't know where this will be hoisted
9018 // until top-level block is fully resolved
9020 top.AddThisReferenceFromChildrenBlock (block.Explicit);
9021 am.SetHasThisAccess ();
9026 protected override Expression DoResolve (ResolveContext ec)
9032 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9034 if (eclass == ExprClass.Unresolved)
9037 if (type.IsClass || type.IsReadOnly) {
9038 if (right_side == EmptyExpression.UnaryAddress)
9039 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
9040 else if (right_side == EmptyExpression.OutAccess)
9041 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
9043 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
9049 public override int GetHashCode()
9051 throw new NotImplementedException ();
9054 public override bool Equals (object obj)
9056 This t = obj as This;
9063 protected override void CloneTo (CloneContext clonectx, Expression t)
9068 public override void SetHasAddressTaken ()
9073 public override object Accept (StructuralVisitor visitor)
9075 return visitor.Visit (this);
9080 /// Represents the `__arglist' construct
9082 public class ArglistAccess : Expression
9084 public ArglistAccess (Location loc)
9089 protected override void CloneTo (CloneContext clonectx, Expression target)
9094 public override bool ContainsEmitWithAwait ()
9099 public override Expression CreateExpressionTree (ResolveContext ec)
9101 throw new NotSupportedException ("ET");
9104 protected override Expression DoResolve (ResolveContext ec)
9106 eclass = ExprClass.Variable;
9107 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
9109 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
9110 ec.Report.Error (190, loc,
9111 "The __arglist construct is valid only within a variable argument method");
9117 public override void Emit (EmitContext ec)
9119 ec.Emit (OpCodes.Arglist);
9122 public override object Accept (StructuralVisitor visitor)
9124 return visitor.Visit (this);
9129 /// Represents the `__arglist (....)' construct
9131 public class Arglist : Expression
9133 Arguments arguments;
9135 public Arglist (Location loc)
9140 public Arglist (Arguments args, Location l)
9146 public Arguments Arguments {
9152 public MetaType[] ArgumentTypes {
9154 if (arguments == null)
9155 return MetaType.EmptyTypes;
9157 var retval = new MetaType[arguments.Count];
9158 for (int i = 0; i < retval.Length; i++)
9159 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9165 public override bool ContainsEmitWithAwait ()
9167 throw new NotImplementedException ();
9170 public override Expression CreateExpressionTree (ResolveContext ec)
9172 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9176 protected override Expression DoResolve (ResolveContext ec)
9178 eclass = ExprClass.Variable;
9179 type = InternalType.Arglist;
9180 if (arguments != null) {
9181 bool dynamic; // Can be ignored as there is always only 1 overload
9182 arguments.Resolve (ec, out dynamic);
9188 public override void Emit (EmitContext ec)
9190 if (arguments != null)
9191 arguments.Emit (ec);
9194 protected override void CloneTo (CloneContext clonectx, Expression t)
9196 Arglist target = (Arglist) t;
9198 if (arguments != null)
9199 target.arguments = arguments.Clone (clonectx);
9202 public override object Accept (StructuralVisitor visitor)
9204 return visitor.Visit (this);
9208 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9210 FullNamedExpression texpr;
9212 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9219 public FullNamedExpression TypeExpression {
9225 public override bool ContainsEmitWithAwait ()
9230 public void AddressOf (EmitContext ec, AddressOp mode)
9233 ec.Emit (OpCodes.Refanyval, type);
9236 protected override Expression DoResolve (ResolveContext rc)
9238 expr = expr.Resolve (rc);
9239 type = texpr.ResolveAsType (rc);
9240 if (expr == null || type == null)
9243 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9244 eclass = ExprClass.Variable;
9248 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9250 return DoResolve (rc);
9253 public override void Emit (EmitContext ec)
9256 ec.Emit (OpCodes.Refanyval, type);
9257 ec.EmitLoadFromPtr (type);
9260 public void Emit (EmitContext ec, bool leave_copy)
9262 throw new NotImplementedException ();
9265 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9268 ec.Emit (OpCodes.Refanyval, type);
9271 LocalTemporary temporary = null;
9273 ec.Emit (OpCodes.Dup);
9274 temporary = new LocalTemporary (source.Type);
9275 temporary.Store (ec);
9278 ec.EmitStoreFromPtr (type);
9280 if (temporary != null) {
9281 temporary.Emit (ec);
9282 temporary.Release (ec);
9286 public override object Accept (StructuralVisitor visitor)
9288 return visitor.Visit (this);
9292 public class RefTypeExpr : ShimExpression
9294 public RefTypeExpr (Expression expr, Location loc)
9300 protected override Expression DoResolve (ResolveContext rc)
9302 expr = expr.Resolve (rc);
9306 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9310 type = rc.BuiltinTypes.Type;
9311 eclass = ExprClass.Value;
9315 public override void Emit (EmitContext ec)
9318 ec.Emit (OpCodes.Refanytype);
9319 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9321 ec.Emit (OpCodes.Call, m);
9324 public override object Accept (StructuralVisitor visitor)
9326 return visitor.Visit (this);
9330 public class MakeRefExpr : ShimExpression
9332 public MakeRefExpr (Expression expr, Location loc)
9338 public override bool ContainsEmitWithAwait ()
9340 throw new NotImplementedException ();
9343 protected override Expression DoResolve (ResolveContext rc)
9345 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9346 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9347 eclass = ExprClass.Value;
9351 public override void Emit (EmitContext ec)
9353 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9354 ec.Emit (OpCodes.Mkrefany, expr.Type);
9357 public override object Accept (StructuralVisitor visitor)
9359 return visitor.Visit (this);
9364 /// Implements the typeof operator
9366 public class TypeOf : Expression {
9367 FullNamedExpression QueriedType;
9370 public TypeOf (FullNamedExpression queried_type, Location l)
9372 QueriedType = queried_type;
9377 // Use this constructor for any compiler generated typeof expression
9379 public TypeOf (TypeSpec type, Location loc)
9381 this.typearg = type;
9387 public override bool IsSideEffectFree {
9393 public TypeSpec TypeArgument {
9399 public FullNamedExpression TypeExpression {
9408 protected override void CloneTo (CloneContext clonectx, Expression t)
9410 TypeOf target = (TypeOf) t;
9411 if (QueriedType != null)
9412 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9415 public override bool ContainsEmitWithAwait ()
9420 public override Expression CreateExpressionTree (ResolveContext ec)
9422 Arguments args = new Arguments (2);
9423 args.Add (new Argument (this));
9424 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9425 return CreateExpressionFactoryCall (ec, "Constant", args);
9428 protected override Expression DoResolve (ResolveContext ec)
9430 if (eclass != ExprClass.Unresolved)
9433 if (typearg == null) {
9435 // Pointer types are allowed without explicit unsafe, they are just tokens
9437 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9438 typearg = QueriedType.ResolveAsType (ec, true);
9441 if (typearg == null)
9444 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9445 ec.Report.Error (1962, QueriedType.Location,
9446 "The typeof operator cannot be used on the dynamic type");
9450 type = ec.BuiltinTypes.Type;
9452 // Even though what is returned is a type object, it's treated as a value by the compiler.
9453 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9454 eclass = ExprClass.Value;
9458 static bool ContainsDynamicType (TypeSpec type)
9460 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9463 var element_container = type as ElementTypeSpec;
9464 if (element_container != null)
9465 return ContainsDynamicType (element_container.Element);
9467 foreach (var t in type.TypeArguments) {
9468 if (ContainsDynamicType (t)) {
9476 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9478 // Target type is not System.Type therefore must be object
9479 // and we need to use different encoding sequence
9480 if (targetType != type)
9483 if (typearg is InflatedTypeSpec) {
9486 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9487 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9488 typearg.GetSignatureForError ());
9492 gt = gt.DeclaringType;
9493 } while (gt != null);
9496 if (ContainsDynamicType (typearg)) {
9497 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9501 enc.EncodeTypeName (typearg);
9504 public override void Emit (EmitContext ec)
9506 ec.Emit (OpCodes.Ldtoken, typearg);
9507 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9509 ec.Emit (OpCodes.Call, m);
9512 public override object Accept (StructuralVisitor visitor)
9514 return visitor.Visit (this);
9518 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9520 public TypeOfMethod (MethodSpec method, Location loc)
9521 : base (method, loc)
9525 protected override Expression DoResolve (ResolveContext ec)
9527 if (member.IsConstructor) {
9528 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9530 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9536 return base.DoResolve (ec);
9539 public override void Emit (EmitContext ec)
9541 ec.Emit (OpCodes.Ldtoken, member);
9544 ec.Emit (OpCodes.Castclass, type);
9547 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9549 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9552 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9554 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9558 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9560 protected readonly T member;
9562 protected TypeOfMember (T member, Location loc)
9564 this.member = member;
9568 public override bool IsSideEffectFree {
9574 public override bool ContainsEmitWithAwait ()
9579 public override Expression CreateExpressionTree (ResolveContext ec)
9581 Arguments args = new Arguments (2);
9582 args.Add (new Argument (this));
9583 args.Add (new Argument (new TypeOf (type, loc)));
9584 return CreateExpressionFactoryCall (ec, "Constant", args);
9587 protected override Expression DoResolve (ResolveContext ec)
9589 eclass = ExprClass.Value;
9593 public override void Emit (EmitContext ec)
9595 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9596 PredefinedMember<MethodSpec> p;
9598 p = GetTypeFromHandleGeneric (ec);
9599 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9601 p = GetTypeFromHandle (ec);
9604 var mi = p.Resolve (loc);
9606 ec.Emit (OpCodes.Call, mi);
9609 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9610 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9613 sealed class TypeOfField : TypeOfMember<FieldSpec>
9615 public TypeOfField (FieldSpec field, Location loc)
9620 protected override Expression DoResolve (ResolveContext ec)
9622 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9626 return base.DoResolve (ec);
9629 public override void Emit (EmitContext ec)
9631 ec.Emit (OpCodes.Ldtoken, member);
9635 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9637 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9640 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9642 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9647 /// Implements the sizeof expression
9649 public class SizeOf : Expression {
9650 readonly Expression texpr;
9651 TypeSpec type_queried;
9653 public SizeOf (Expression queried_type, Location l)
9655 this.texpr = queried_type;
9659 public override bool IsSideEffectFree {
9665 public Expression TypeExpression {
9671 public override bool ContainsEmitWithAwait ()
9676 public override Expression CreateExpressionTree (ResolveContext ec)
9678 Error_PointerInsideExpressionTree (ec);
9682 protected override Expression DoResolve (ResolveContext ec)
9684 type_queried = texpr.ResolveAsType (ec);
9685 if (type_queried == null)
9688 if (type_queried.IsEnum)
9689 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9691 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9693 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9696 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9701 ec.Report.Error (233, loc,
9702 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9703 type_queried.GetSignatureForError ());
9706 type = ec.BuiltinTypes.Int;
9707 eclass = ExprClass.Value;
9711 public override void Emit (EmitContext ec)
9713 ec.Emit (OpCodes.Sizeof, type_queried);
9716 protected override void CloneTo (CloneContext clonectx, Expression t)
9720 public override object Accept (StructuralVisitor visitor)
9722 return visitor.Visit (this);
9727 /// Implements the qualified-alias-member (::) expression.
9729 public class QualifiedAliasMember : MemberAccess
9731 readonly string alias;
9732 public static readonly string GlobalAlias = "global";
9734 public QualifiedAliasMember (string alias, string identifier, Location l)
9735 : base (null, identifier, l)
9740 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9741 : base (null, identifier, targs, l)
9746 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9747 : base (null, identifier, arity, l)
9752 public string Alias {
9758 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9760 if (alias == GlobalAlias)
9761 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9763 int errors = mc.Module.Compiler.Report.Errors;
9764 var expr = mc.LookupNamespaceAlias (alias);
9766 if (errors == mc.Module.Compiler.Report.Errors)
9767 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9775 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9777 expr = CreateExpressionFromAlias (mc);
9781 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9784 protected override Expression DoResolve (ResolveContext rc)
9786 return ResolveAsTypeOrNamespace (rc, false);
9789 public override string GetSignatureForError ()
9792 if (targs != null) {
9793 name = Name + "<" + targs.GetSignatureForError () + ">";
9796 return alias + "::" + name;
9799 public override bool HasConditionalAccess ()
9804 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9806 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9807 rc.Module.Compiler.Report.Error (687, loc,
9808 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9809 GetSignatureForError ());
9814 return DoResolve (rc);
9817 protected override void CloneTo (CloneContext clonectx, Expression t)
9822 public override object Accept (StructuralVisitor visitor)
9824 return visitor.Visit (this);
9829 /// Implements the member access expression
9831 public class MemberAccess : ATypeNameExpression
9833 protected Expression expr;
9835 public MemberAccess (Expression expr, string id)
9836 : base (id, expr.Location)
9841 public MemberAccess (Expression expr, string identifier, Location loc)
9842 : base (identifier, loc)
9847 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9848 : base (identifier, args, loc)
9853 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9854 : base (identifier, arity, loc)
9859 public Expression LeftExpression {
9865 public override Location StartLocation {
9867 return expr == null ? loc : expr.StartLocation;
9871 protected override Expression DoResolve (ResolveContext rc)
9873 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9875 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9880 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9882 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9884 if (e is TypeExpr) {
9885 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9890 e = e.ResolveLValue (rc, rhs);
9895 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9897 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9898 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9900 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9903 public override bool HasConditionalAccess ()
9905 return LeftExpression.HasConditionalAccess ();
9908 public static bool IsValidDotExpression (TypeSpec type)
9910 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9911 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9913 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9916 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9918 var sn = expr as SimpleName;
9919 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9922 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9925 // Resolve expression which does have type set as we need expression type
9926 // with disable flow analysis as we don't know whether left side expression
9927 // is used as variable or type
9929 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9930 expr = expr.Resolve (rc);
9931 } else if (expr is TypeParameterExpr) {
9932 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9936 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9937 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9938 expr = expr.Resolve (rc, flags);
9941 expr = expr.Resolve (rc, flags);
9948 var ns = expr as NamespaceExpression;
9950 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9952 if (retval == null) {
9953 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9958 if (HasTypeArguments)
9959 return new GenericTypeExpr (retval.Type, targs, loc);
9961 targs.Resolve (rc, false);
9967 var cma = this as ConditionalMemberAccess;
9970 TypeSpec expr_type = expr.Type;
9971 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9972 me = expr as MemberExpr;
9974 me.ResolveInstanceExpression (rc, null);
9976 Arguments args = new Arguments (1);
9977 args.Add (new Argument (expr));
9980 return new DynamicConditionalMemberBinder (Name, args, loc);
9982 return new DynamicMemberBinder (Name, args, loc);
9986 if (!IsNullPropagatingValid (expr.Type)) {
9987 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9991 if (expr_type.IsNullableType) {
9992 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9993 expr_type = expr.Type;
9997 if (!IsValidDotExpression (expr_type)) {
9998 Error_OperatorCannotBeApplied (rc, expr_type);
10002 var lookup_arity = Arity;
10003 bool errorMode = false;
10004 Expression member_lookup;
10006 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
10007 if (member_lookup == null) {
10009 // Try to look for extension method when member lookup failed
10011 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10012 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
10013 if (methods != null) {
10014 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
10015 if (HasTypeArguments) {
10016 if (!targs.Resolve (rc, false))
10019 emg.SetTypeArguments (rc, targs);
10023 emg.ConditionalAccess = true;
10025 // TODO: it should really skip the checks bellow
10026 return emg.Resolve (rc);
10032 if (member_lookup == null) {
10033 var dep = expr_type.GetMissingDependencies ();
10035 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
10036 } else if (expr is TypeExpr) {
10037 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
10039 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
10045 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
10046 // Leave it to overload resolution to report correct error
10047 } else if (!(member_lookup is TypeExpr)) {
10048 // TODO: rc.SymbolRelatedToPreviousError
10049 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
10054 if (member_lookup != null)
10058 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
10062 TypeExpr texpr = member_lookup as TypeExpr;
10063 if (texpr != null) {
10064 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
10065 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
10066 Name, texpr.GetSignatureForError ());
10069 if (!texpr.Type.IsAccessible (rc)) {
10070 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
10071 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
10075 if (HasTypeArguments) {
10076 return new GenericTypeExpr (member_lookup.Type, targs, loc);
10079 return member_lookup;
10082 me = member_lookup as MemberExpr;
10084 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
10089 me.ConditionalAccess = true;
10092 me = me.ResolveMemberAccess (rc, expr, sn);
10095 if (!targs.Resolve (rc, false))
10098 me.SetTypeArguments (rc, targs);
10104 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
10106 FullNamedExpression fexpr = expr as FullNamedExpression;
10107 if (fexpr == null) {
10108 expr.ResolveAsType (rc);
10112 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
10114 if (expr_resolved == null)
10117 var ns = expr_resolved as NamespaceExpression;
10119 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10121 if (retval == null) {
10122 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10123 } else if (Arity > 0) {
10124 if (HasTypeArguments) {
10125 retval = new GenericTypeExpr (retval.Type, targs, loc);
10126 if (retval.ResolveAsType (rc) == null)
10129 targs.Resolve (rc, allowUnboundTypeArguments);
10131 retval = new GenericOpenTypeExpr (retval.Type, loc);
10138 var tnew_expr = expr_resolved.ResolveAsType (rc);
10139 if (tnew_expr == null)
10142 TypeSpec expr_type = tnew_expr;
10143 if (TypeManager.IsGenericParameter (expr_type)) {
10144 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10145 tnew_expr.GetSignatureForError ());
10149 var qam = this as QualifiedAliasMember;
10151 rc.Module.Compiler.Report.Error (431, loc,
10152 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10157 TypeSpec nested = null;
10158 while (expr_type != null) {
10159 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10160 if (nested == null) {
10161 if (expr_type == tnew_expr) {
10162 Error_IdentifierNotFound (rc, expr_type);
10166 expr_type = tnew_expr;
10167 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10168 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10172 if (nested.IsAccessible (rc))
10176 // Keep looking after inaccessible candidate but only if
10177 // we are not in same context as the definition itself
10179 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10182 expr_type = expr_type.BaseType;
10187 if (HasTypeArguments) {
10188 texpr = new GenericTypeExpr (nested, targs, loc);
10190 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10192 texpr = new GenericOpenTypeExpr (nested, loc);
10194 } else if (expr_resolved is GenericOpenTypeExpr) {
10195 texpr = new GenericOpenTypeExpr (nested, loc);
10197 texpr = new TypeExpression (nested, loc);
10200 if (texpr.ResolveAsType (rc) == null)
10206 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10208 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10210 if (nested != null) {
10211 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10215 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10216 if (any_other_member != null) {
10217 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10221 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10222 Name, expr_type.GetSignatureForError ());
10225 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10227 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10230 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10232 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10233 ec.Report.SymbolRelatedToPreviousError (type);
10235 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10237 // a using directive or an assembly reference
10238 if (cand != null) {
10239 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10241 missing = "an assembly reference";
10244 ec.Report.Error (1061, loc,
10245 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10246 type.GetSignatureForError (), name, missing);
10250 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10253 public override string GetSignatureForError ()
10255 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10258 protected override void CloneTo (CloneContext clonectx, Expression t)
10260 MemberAccess target = (MemberAccess) t;
10262 target.expr = expr.Clone (clonectx);
10265 public override object Accept (StructuralVisitor visitor)
10267 return visitor.Visit (this);
10271 public class ConditionalMemberAccess : MemberAccess
10273 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10274 : base (expr, identifier, args, loc)
10278 public override bool HasConditionalAccess ()
10285 /// Implements checked expressions
10287 public class CheckedExpr : Expression {
10289 public Expression Expr;
10291 public CheckedExpr (Expression e, Location l)
10297 public override bool ContainsEmitWithAwait ()
10299 return Expr.ContainsEmitWithAwait ();
10302 public override Expression CreateExpressionTree (ResolveContext ec)
10304 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10305 return Expr.CreateExpressionTree (ec);
10308 protected override Expression DoResolve (ResolveContext ec)
10310 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10311 Expr = Expr.Resolve (ec);
10316 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10319 eclass = Expr.eclass;
10324 public override void Emit (EmitContext ec)
10326 using (ec.With (EmitContext.Options.CheckedScope, true))
10330 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10332 using (ec.With (EmitContext.Options.CheckedScope, true))
10333 Expr.EmitBranchable (ec, target, on_true);
10336 public override void FlowAnalysis (FlowAnalysisContext fc)
10338 Expr.FlowAnalysis (fc);
10341 public override SLE.Expression MakeExpression (BuilderContext ctx)
10343 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10344 return Expr.MakeExpression (ctx);
10348 protected override void CloneTo (CloneContext clonectx, Expression t)
10350 CheckedExpr target = (CheckedExpr) t;
10352 target.Expr = Expr.Clone (clonectx);
10355 public override object Accept (StructuralVisitor visitor)
10357 return visitor.Visit (this);
10362 /// Implements the unchecked expression
10364 public class UnCheckedExpr : Expression {
10366 public Expression Expr;
10368 public UnCheckedExpr (Expression e, Location l)
10374 public override bool ContainsEmitWithAwait ()
10376 return Expr.ContainsEmitWithAwait ();
10379 public override Expression CreateExpressionTree (ResolveContext ec)
10381 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10382 return Expr.CreateExpressionTree (ec);
10385 protected override Expression DoResolve (ResolveContext ec)
10387 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10388 Expr = Expr.Resolve (ec);
10393 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10396 eclass = Expr.eclass;
10401 public override void Emit (EmitContext ec)
10403 using (ec.With (EmitContext.Options.CheckedScope, false))
10407 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10409 using (ec.With (EmitContext.Options.CheckedScope, false))
10410 Expr.EmitBranchable (ec, target, on_true);
10413 public override void FlowAnalysis (FlowAnalysisContext fc)
10415 Expr.FlowAnalysis (fc);
10418 protected override void CloneTo (CloneContext clonectx, Expression t)
10420 UnCheckedExpr target = (UnCheckedExpr) t;
10422 target.Expr = Expr.Clone (clonectx);
10425 public override object Accept (StructuralVisitor visitor)
10427 return visitor.Visit (this);
10432 /// An Element Access expression.
10434 /// During semantic analysis these are transformed into
10435 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10437 public class ElementAccess : Expression
10439 public Arguments Arguments;
10440 public Expression Expr;
10441 bool conditional_access_receiver;
10443 public ElementAccess (Expression e, Arguments args, Location loc)
10447 this.Arguments = args;
10450 public bool ConditionalAccess { get; set; }
10452 public override Location StartLocation {
10454 return Expr.StartLocation;
10458 public override bool ContainsEmitWithAwait ()
10460 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10464 // We perform some simple tests, and then to "split" the emit and store
10465 // code we create an instance of a different class, and return that.
10467 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10469 if (conditionalAccessReceiver)
10470 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10472 Expr = Expr.Resolve (ec);
10474 if (conditionalAccessReceiver)
10475 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10482 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10483 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10487 if (type.IsArray) {
10488 var aa = new ArrayAccess (this, loc) {
10489 ConditionalAccess = ConditionalAccess,
10492 if (conditionalAccessReceiver)
10493 aa.SetConditionalAccessReceiver ();
10498 if (type.IsPointer)
10499 return Expr.MakePointerAccess (ec, type, Arguments);
10501 FieldExpr fe = Expr as FieldExpr;
10503 var ff = fe.Spec as FixedFieldSpec;
10505 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10509 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10510 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10511 var indexer = new IndexerExpr (indexers, type, this) {
10512 ConditionalAccess = ConditionalAccess
10515 if (conditionalAccessReceiver)
10516 indexer.SetConditionalAccessReceiver ();
10521 Error_CannotApplyIndexing (ec, type, loc);
10526 public override Expression CreateExpressionTree (ResolveContext ec)
10528 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10529 Expr.CreateExpressionTree (ec));
10531 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10534 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10536 if (type != InternalType.ErrorType) {
10537 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10538 type.GetSignatureForError ());
10542 public override bool HasConditionalAccess ()
10544 return ConditionalAccess || Expr.HasConditionalAccess ();
10547 void ResolveConditionalAccessReceiver (ResolveContext rc)
10549 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10550 conditional_access_receiver = true;
10554 protected override Expression DoResolve (ResolveContext rc)
10556 ResolveConditionalAccessReceiver (rc);
10558 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10562 return expr.Resolve (rc);
10565 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10567 var res = CreateAccessExpression (ec, false);
10571 return res.ResolveLValue (ec, rhs);
10574 public override void Emit (EmitContext ec)
10576 throw new Exception ("Should never be reached");
10579 public override void FlowAnalysis (FlowAnalysisContext fc)
10581 Expr.FlowAnalysis (fc);
10583 Arguments.FlowAnalysis (fc);
10586 public override string GetSignatureForError ()
10588 return Expr.GetSignatureForError ();
10591 protected override void CloneTo (CloneContext clonectx, Expression t)
10593 ElementAccess target = (ElementAccess) t;
10595 target.Expr = Expr.Clone (clonectx);
10596 if (Arguments != null)
10597 target.Arguments = Arguments.Clone (clonectx);
10600 public override object Accept (StructuralVisitor visitor)
10602 return visitor.Visit (this);
10607 /// Implements array access
10609 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10611 // Points to our "data" repository
10615 LocalTemporary temp;
10617 bool? has_await_args;
10618 bool conditional_access_receiver;
10620 public ArrayAccess (ElementAccess ea_data, Location l)
10626 public bool ConditionalAccess { get; set; }
10628 public void AddressOf (EmitContext ec, AddressOp mode)
10630 var ac = (ArrayContainer) ea.Expr.Type;
10632 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10633 LoadInstanceAndArguments (ec, false, true);
10636 LoadInstanceAndArguments (ec, false, false);
10638 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10639 ec.Emit (OpCodes.Readonly);
10641 ec.EmitArrayAddress (ac);
10644 public override Expression CreateExpressionTree (ResolveContext ec)
10646 if (ConditionalAccess)
10647 Error_NullShortCircuitInsideExpressionTree (ec);
10649 return ea.CreateExpressionTree (ec);
10652 public override bool ContainsEmitWithAwait ()
10654 return ea.ContainsEmitWithAwait ();
10657 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10659 if (HasConditionalAccess ())
10660 Error_NullPropagatingLValue (ec);
10662 return DoResolve (ec);
10665 protected override Expression DoResolve (ResolveContext ec)
10667 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10669 ea.Arguments.Resolve (ec, out dynamic);
10671 var ac = ea.Expr.Type as ArrayContainer;
10672 int rank = ea.Arguments.Count;
10673 if (ac.Rank != rank) {
10674 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10675 rank.ToString (), ac.Rank.ToString ());
10680 if (type.IsPointer) {
10681 if (ec.CurrentIterator != null) {
10682 UnsafeInsideIteratorError (ec, ea.Location);
10683 } else if (!ec.IsUnsafe) {
10684 UnsafeError (ec, ea.Location);
10688 if (conditional_access_receiver)
10689 type = LiftMemberType (ec, type);
10691 foreach (Argument a in ea.Arguments) {
10692 var na = a as NamedArgument;
10694 ElementAccess.Error_NamedArgument (na, ec.Report);
10696 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10699 eclass = ExprClass.Variable;
10704 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10706 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10709 public override void FlowAnalysis (FlowAnalysisContext fc)
10711 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10713 ea.FlowAnalysis (fc);
10715 if (conditional_access_receiver)
10716 fc.DefiniteAssignment = da;
10719 public override bool HasConditionalAccess ()
10721 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10725 // Load the array arguments into the stack.
10727 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10729 if (prepareAwait) {
10730 ea.Expr = ea.Expr.EmitToField (ec);
10732 var ie = new InstanceEmitter (ea.Expr, false);
10733 ie.Emit (ec, ConditionalAccess);
10735 if (duplicateArguments) {
10736 ec.Emit (OpCodes.Dup);
10738 var copy = new LocalTemporary (ea.Expr.Type);
10744 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10745 if (dup_args != null)
10746 ea.Arguments = dup_args;
10749 public void Emit (EmitContext ec, bool leave_copy)
10752 ec.EmitLoadFromPtr (type);
10754 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10755 LoadInstanceAndArguments (ec, false, true);
10758 if (conditional_access_receiver)
10759 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10761 var ac = (ArrayContainer) ea.Expr.Type;
10762 LoadInstanceAndArguments (ec, false, false);
10763 ec.EmitArrayLoad (ac);
10765 if (conditional_access_receiver)
10766 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10770 ec.Emit (OpCodes.Dup);
10771 temp = new LocalTemporary (this.type);
10776 public override void Emit (EmitContext ec)
10781 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10783 var ac = (ArrayContainer) ea.Expr.Type;
10784 TypeSpec t = source.Type;
10786 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10789 // When we are dealing with a struct, get the address of it to avoid value copy
10790 // Same cannot be done for reference type because array covariance and the
10791 // check in ldelema requires to specify the type of array element stored at the index
10793 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10794 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10796 if (has_await_args.Value) {
10797 if (source.ContainsEmitWithAwait ()) {
10798 source = source.EmitToField (ec);
10799 isCompound = false;
10803 LoadInstanceAndArguments (ec, isCompound, false);
10808 ec.EmitArrayAddress (ac);
10811 ec.Emit (OpCodes.Dup);
10815 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10817 if (has_await_args.Value) {
10818 if (source.ContainsEmitWithAwait ())
10819 source = source.EmitToField (ec);
10821 LoadInstanceAndArguments (ec, false, false);
10828 var lt = ea.Expr as LocalTemporary;
10834 ec.Emit (OpCodes.Dup);
10835 temp = new LocalTemporary (this.type);
10840 ec.EmitStoreFromPtr (t);
10842 ec.EmitArrayStore (ac);
10845 if (temp != null) {
10851 public override Expression EmitToField (EmitContext ec)
10854 // Have to be specialized for arrays to get access to
10855 // underlying element. Instead of another result copy we
10856 // need direct access to element
10860 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10862 ea.Expr = ea.Expr.EmitToField (ec);
10863 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10867 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10869 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10872 public override SLE.Expression MakeExpression (BuilderContext ctx)
10874 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10877 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10879 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10880 return Arguments.MakeExpression (ea.Arguments, ctx);
10884 public void SetConditionalAccessReceiver ()
10886 conditional_access_receiver = true;
10891 // Indexer access expression
10893 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10895 IList<MemberSpec> indexers;
10896 Arguments arguments;
10897 TypeSpec queried_type;
10899 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10900 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10904 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10907 this.indexers = indexers;
10908 this.queried_type = queriedType;
10909 this.InstanceExpression = instance;
10910 this.arguments = args;
10915 protected override Arguments Arguments {
10924 protected override TypeSpec DeclaringType {
10926 return best_candidate.DeclaringType;
10930 public override bool IsInstance {
10936 public override bool IsStatic {
10942 public override string KindName {
10943 get { return "indexer"; }
10946 public override string Name {
10954 public override bool ContainsEmitWithAwait ()
10956 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10959 public override Expression CreateExpressionTree (ResolveContext ec)
10961 if (ConditionalAccess) {
10962 Error_NullShortCircuitInsideExpressionTree (ec);
10965 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10966 InstanceExpression.CreateExpressionTree (ec),
10967 new TypeOfMethod (Getter, loc));
10969 return CreateExpressionFactoryCall (ec, "Call", args);
10972 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10974 LocalTemporary await_source_arg = null;
10977 emitting_compound_assignment = true;
10978 if (source is DynamicExpressionStatement) {
10983 emitting_compound_assignment = false;
10985 if (has_await_arguments) {
10986 await_source_arg = new LocalTemporary (Type);
10987 await_source_arg.Store (ec);
10989 arguments.Add (new Argument (await_source_arg));
10992 temp = await_source_arg;
10995 has_await_arguments = false;
11000 ec.Emit (OpCodes.Dup);
11001 temp = new LocalTemporary (Type);
11007 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
11008 source = source.EmitToField (ec);
11010 temp = new LocalTemporary (Type);
11017 arguments.Add (new Argument (source));
11020 var call = new CallEmitter ();
11021 call.InstanceExpression = InstanceExpression;
11022 if (arguments == null)
11023 call.InstanceExpressionOnStack = true;
11025 call.Emit (ec, Setter, arguments, loc);
11027 if (temp != null) {
11030 } else if (leave_copy) {
11034 if (await_source_arg != null) {
11035 await_source_arg.Release (ec);
11039 public override void FlowAnalysis (FlowAnalysisContext fc)
11041 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
11043 base.FlowAnalysis (fc);
11044 arguments.FlowAnalysis (fc);
11046 if (conditional_access_receiver)
11047 fc.DefiniteAssignment = da;
11050 public override string GetSignatureForError ()
11052 return best_candidate.GetSignatureForError ();
11055 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
11058 throw new NotSupportedException ();
11060 var value = new[] { source.MakeExpression (ctx) };
11061 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
11062 return SLE.Expression.Block (
11063 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
11068 public override SLE.Expression MakeExpression (BuilderContext ctx)
11071 return base.MakeExpression (ctx);
11073 var args = Arguments.MakeExpression (arguments, ctx);
11074 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
11078 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
11080 if (best_candidate != null)
11083 eclass = ExprClass.IndexerAccess;
11086 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
11087 arguments.Resolve (rc, out dynamic);
11090 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11093 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
11094 res.BaseMembersProvider = this;
11095 res.InstanceQualifier = this;
11097 // TODO: Do I need 2 argument sets?
11098 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
11099 if (best_candidate != null)
11100 type = res.BestCandidateReturnType;
11101 else if (!res.BestCandidateIsDynamic)
11106 // It has dynamic arguments
11109 Arguments args = new Arguments (arguments.Count + 1);
11111 rc.Report.Error (1972, loc,
11112 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
11114 args.Add (new Argument (InstanceExpression));
11116 args.AddRange (arguments);
11118 best_candidate = null;
11119 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11123 // Try to avoid resolving left expression again
11125 if (right_side != null)
11126 ResolveInstanceExpression (rc, right_side);
11131 protected override void CloneTo (CloneContext clonectx, Expression t)
11133 IndexerExpr target = (IndexerExpr) t;
11135 if (arguments != null)
11136 target.arguments = arguments.Clone (clonectx);
11139 public void SetConditionalAccessReceiver ()
11141 conditional_access_receiver = true;
11144 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11146 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11149 #region IBaseMembersProvider Members
11151 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11153 var baseType = type.BaseType;
11154 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11156 if (members == null && !type.IsInterface) {
11157 var tps = queried_type as TypeParameterSpec;
11159 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11165 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11167 if (queried_type == member.DeclaringType)
11170 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11171 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11174 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11183 // A base access expression
11185 public class BaseThis : This
11187 public BaseThis (Location loc)
11192 public BaseThis (TypeSpec type, Location loc)
11196 eclass = ExprClass.Variable;
11201 public override string Name {
11209 public override Expression CreateExpressionTree (ResolveContext ec)
11211 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11212 return base.CreateExpressionTree (ec);
11215 public override void Emit (EmitContext ec)
11219 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11220 var context_type = ec.CurrentType;
11221 ec.Emit (OpCodes.Ldobj, context_type);
11222 ec.Emit (OpCodes.Box, context_type);
11226 protected override void Error_ThisNotAvailable (ResolveContext ec)
11229 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11231 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11235 public override void ResolveBase (ResolveContext ec)
11237 base.ResolveBase (ec);
11238 type = ec.CurrentType.BaseType;
11241 public override object Accept (StructuralVisitor visitor)
11243 return visitor.Visit (this);
11248 /// This class exists solely to pass the Type around and to be a dummy
11249 /// that can be passed to the conversion functions (this is used by
11250 /// foreach implementation to typecast the object return value from
11251 /// get_Current into the proper type. All code has been generated and
11252 /// we only care about the side effect conversions to be performed
11254 /// This is also now used as a placeholder where a no-action expression
11255 /// is needed (the `New' class).
11257 public class EmptyExpression : Expression
11259 sealed class OutAccessExpression : EmptyExpression
11261 public OutAccessExpression (TypeSpec t)
11266 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11268 rc.Report.Error (206, right_side.Location,
11269 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11275 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11276 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11277 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11278 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11279 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11280 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11281 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11282 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11284 public EmptyExpression (TypeSpec t)
11287 eclass = ExprClass.Value;
11288 loc = Location.Null;
11291 protected override void CloneTo (CloneContext clonectx, Expression target)
11295 public override bool ContainsEmitWithAwait ()
11300 public override Expression CreateExpressionTree (ResolveContext ec)
11302 throw new NotSupportedException ("ET");
11305 protected override Expression DoResolve (ResolveContext ec)
11310 public override void Emit (EmitContext ec)
11312 // nothing, as we only exist to not do anything.
11315 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11319 public override void EmitSideEffect (EmitContext ec)
11323 public override object Accept (StructuralVisitor visitor)
11325 return visitor.Visit (this);
11329 sealed class EmptyAwaitExpression : EmptyExpression
11331 public EmptyAwaitExpression (TypeSpec type)
11336 public override bool ContainsEmitWithAwait ()
11343 // Empty statement expression
11345 public sealed class EmptyExpressionStatement : ExpressionStatement
11347 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11349 private EmptyExpressionStatement ()
11351 loc = Location.Null;
11354 public override bool ContainsEmitWithAwait ()
11359 public override Expression CreateExpressionTree (ResolveContext ec)
11364 public override void EmitStatement (EmitContext ec)
11369 protected override Expression DoResolve (ResolveContext ec)
11371 eclass = ExprClass.Value;
11372 type = ec.BuiltinTypes.Object;
11376 public override void Emit (EmitContext ec)
11381 public override object Accept (StructuralVisitor visitor)
11383 return visitor.Visit (this);
11387 public class ErrorExpression : EmptyExpression
11389 public static readonly ErrorExpression Instance = new ErrorExpression ();
11391 private ErrorExpression ()
11392 : base (InternalType.ErrorType)
11396 public override Expression CreateExpressionTree (ResolveContext ec)
11401 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11406 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11410 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11414 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11418 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11422 public override object Accept (StructuralVisitor visitor)
11424 return visitor.Visit (this);
11428 public class UserCast : Expression {
11432 public UserCast (MethodSpec method, Expression source, Location l)
11434 if (source == null)
11435 throw new ArgumentNullException ("source");
11437 this.method = method;
11438 this.source = source;
11439 type = method.ReturnType;
11443 public Expression Source {
11452 public override bool ContainsEmitWithAwait ()
11454 return source.ContainsEmitWithAwait ();
11457 public override Expression CreateExpressionTree (ResolveContext ec)
11459 Arguments args = new Arguments (3);
11460 args.Add (new Argument (source.CreateExpressionTree (ec)));
11461 args.Add (new Argument (new TypeOf (type, loc)));
11462 args.Add (new Argument (new TypeOfMethod (method, loc)));
11463 return CreateExpressionFactoryCall (ec, "Convert", args);
11466 protected override Expression DoResolve (ResolveContext ec)
11468 method.CheckObsoleteness (ec, source.Location);
11470 eclass = ExprClass.Value;
11474 public override void Emit (EmitContext ec)
11477 ec.MarkCallEntry (loc);
11478 ec.Emit (OpCodes.Call, method);
11481 public override void FlowAnalysis (FlowAnalysisContext fc)
11483 source.FlowAnalysis (fc);
11486 public override string GetSignatureForError ()
11488 return TypeManager.CSharpSignature (method);
11491 public override SLE.Expression MakeExpression (BuilderContext ctx)
11494 return base.MakeExpression (ctx);
11496 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11502 // Holds additional type specifiers like ?, *, []
11504 public class ComposedTypeSpecifier
11506 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11508 public readonly int Dimension;
11509 public readonly Location Location;
11511 public ComposedTypeSpecifier (int specifier, Location loc)
11513 this.Dimension = specifier;
11514 this.Location = loc;
11518 public bool IsNullable {
11520 return Dimension == -1;
11524 public bool IsPointer {
11526 return Dimension == -2;
11530 public ComposedTypeSpecifier Next { get; set; }
11534 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11536 return new ComposedTypeSpecifier (dimension, loc);
11539 public static ComposedTypeSpecifier CreateNullable (Location loc)
11541 return new ComposedTypeSpecifier (-1, loc);
11544 public static ComposedTypeSpecifier CreatePointer (Location loc)
11546 return new ComposedTypeSpecifier (-2, loc);
11549 public string GetSignatureForError ()
11554 ArrayContainer.GetPostfixSignature (Dimension);
11556 return Next != null ? s + Next.GetSignatureForError () : s;
11561 // This class is used to "construct" the type during a typecast
11562 // operation. Since the Type.GetType class in .NET can parse
11563 // the type specification, we just use this to construct the type
11564 // one bit at a time.
11566 public class ComposedCast : TypeExpr {
11567 FullNamedExpression left;
11568 ComposedTypeSpecifier spec;
11570 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11573 throw new ArgumentNullException ("spec");
11577 this.loc = left.Location;
11580 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11582 type = left.ResolveAsType (ec);
11586 eclass = ExprClass.Type;
11588 var single_spec = spec;
11590 if (single_spec.IsNullable) {
11591 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11595 single_spec = single_spec.Next;
11596 } else if (single_spec.IsPointer) {
11598 // Declared fields cannot have unmanaged check done before all types are defined
11600 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11603 var rc = ec as ResolveContext;
11604 if (rc?.CurrentIterator != null) {
11605 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11606 } else if (!ec.IsUnsafe) {
11607 UnsafeError (ec.Module.Compiler.Report, loc);
11611 type = PointerContainer.MakeType (ec.Module, type);
11612 single_spec = single_spec.Next;
11613 } while (single_spec != null && single_spec.IsPointer);
11616 if (single_spec != null && single_spec.Dimension > 0) {
11617 if (type.IsSpecialRuntimeType) {
11618 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11619 } else if (type.IsStatic) {
11620 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11621 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11622 type.GetSignatureForError ());
11624 MakeArray (ec.Module, single_spec);
11631 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11633 if (spec.Next != null)
11634 MakeArray (module, spec.Next);
11636 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11639 public override string GetSignatureForError ()
11641 return left.GetSignatureForError () + spec.GetSignatureForError ();
11644 public override object Accept (StructuralVisitor visitor)
11646 return visitor.Visit (this);
11650 class ReferenceTypeExpr : TypeExpr
11652 FullNamedExpression element;
11654 public ReferenceTypeExpr (FullNamedExpression element, Location loc)
11656 this.element = element;
11660 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
11662 type = element.ResolveAsType (mc);
11666 eclass = ExprClass.Type;
11667 type = ReferenceContainer.MakeType (mc.Module, type);
11672 public override string GetSignatureForError ()
11674 return "ref " + element.GetSignatureForError ();
11677 public override object Accept (StructuralVisitor visitor)
11679 return visitor.Visit (this);
11683 class FixedBufferPtr : Expression
11685 readonly Expression array;
11687 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11689 this.type = array_type;
11690 this.array = array;
11694 public override bool ContainsEmitWithAwait ()
11696 throw new NotImplementedException ();
11699 public override Expression CreateExpressionTree (ResolveContext ec)
11701 Error_PointerInsideExpressionTree (ec);
11705 public override void Emit(EmitContext ec)
11710 protected override Expression DoResolve (ResolveContext ec)
11712 type = PointerContainer.MakeType (ec.Module, type);
11713 eclass = ExprClass.Value;
11720 // This class is used to represent the address of an array, used
11721 // only by the Fixed statement, this generates "&a [0]" construct
11722 // for fixed (char *pa = a)
11724 class ArrayPtr : FixedBufferPtr
11726 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11727 base (array, array_type, l)
11731 public override void Emit (EmitContext ec)
11736 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11741 // Encapsulates a conversion rules required for array indexes
11743 public class ArrayIndexCast : TypeCast
11745 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11746 : base (expr, returnType)
11748 if (expr.Type == returnType) // int -> int
11749 throw new ArgumentException ("unnecessary array index conversion");
11752 public override Expression CreateExpressionTree (ResolveContext ec)
11754 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11755 return base.CreateExpressionTree (ec);
11759 public override void Emit (EmitContext ec)
11763 switch (child.Type.BuiltinType) {
11764 case BuiltinTypeSpec.Type.UInt:
11765 ec.Emit (OpCodes.Conv_U);
11767 case BuiltinTypeSpec.Type.Long:
11768 ec.Emit (OpCodes.Conv_Ovf_I);
11770 case BuiltinTypeSpec.Type.ULong:
11771 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11774 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11780 // Implements the `stackalloc' keyword
11782 public class StackAlloc : Expression {
11787 public StackAlloc (Expression type, Expression count, Location l)
11790 this.count = count;
11794 public Expression TypeExpression {
11800 public Expression CountExpression {
11806 public override bool ContainsEmitWithAwait ()
11811 public override Expression CreateExpressionTree (ResolveContext ec)
11813 throw new NotSupportedException ("ET");
11816 protected override Expression DoResolve (ResolveContext ec)
11818 count = count.Resolve (ec);
11822 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11823 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11828 Constant c = count as Constant;
11829 if (c != null && c.IsNegative) {
11830 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11833 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11834 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11837 otype = texpr.ResolveAsType (ec);
11841 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11844 type = PointerContainer.MakeType (ec.Module, otype);
11845 eclass = ExprClass.Value;
11850 public override void Emit (EmitContext ec)
11852 int size = BuiltinTypeSpec.GetSize (otype);
11857 ec.Emit (OpCodes.Sizeof, otype);
11861 ec.Emit (OpCodes.Mul_Ovf_Un);
11862 ec.Emit (OpCodes.Localloc);
11865 protected override void CloneTo (CloneContext clonectx, Expression t)
11867 StackAlloc target = (StackAlloc) t;
11868 target.count = count.Clone (clonectx);
11869 target.texpr = texpr.Clone (clonectx);
11872 public override object Accept (StructuralVisitor visitor)
11874 return visitor.Visit (this);
11879 // An object initializer expression
11881 public class ElementInitializer : Assign
11883 public readonly string Name;
11885 public ElementInitializer (string name, Expression initializer, Location loc)
11886 : base (null, initializer, loc)
11891 public bool IsDictionaryInitializer {
11893 return Name == null;
11897 protected override void CloneTo (CloneContext clonectx, Expression t)
11899 ElementInitializer target = (ElementInitializer) t;
11900 target.source = source.Clone (clonectx);
11903 public override Expression CreateExpressionTree (ResolveContext ec)
11905 Arguments args = new Arguments (2);
11906 FieldExpr fe = target as FieldExpr;
11908 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11910 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11913 Expression arg_expr;
11914 var cinit = source as CollectionOrObjectInitializers;
11915 if (cinit == null) {
11917 arg_expr = source.CreateExpressionTree (ec);
11919 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11920 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11923 args.Add (new Argument (arg_expr));
11924 return CreateExpressionFactoryCall (ec, mname, args);
11927 protected override Expression DoResolve (ResolveContext ec)
11929 if (source == null)
11930 return EmptyExpressionStatement.Instance;
11932 if (!ResolveElement (ec))
11935 if (source is CollectionOrObjectInitializers) {
11936 target = target.Resolve (ec);
11937 if (target == null)
11940 Expression previous = ec.CurrentInitializerVariable;
11941 ec.CurrentInitializerVariable = target;
11942 source = source.Resolve (ec);
11943 ec.CurrentInitializerVariable = previous;
11944 if (source == null)
11947 eclass = source.eclass;
11948 type = source.Type;
11953 return base.DoResolve (ec);
11956 public override void EmitStatement (EmitContext ec)
11958 if (source is CollectionOrObjectInitializers)
11961 base.EmitStatement (ec);
11964 protected virtual bool ResolveElement (ResolveContext rc)
11966 var t = rc.CurrentInitializerVariable.Type;
11967 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11968 Arguments args = new Arguments (1);
11969 args.Add (new Argument (rc.CurrentInitializerVariable));
11970 target = new DynamicMemberBinder (Name, args, loc);
11972 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11973 if (member == null) {
11974 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11976 if (member != null) {
11977 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11978 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11983 if (member == null) {
11984 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11988 var me = member as MemberExpr;
11989 if (me is EventExpr) {
11990 me = me.ResolveMemberAccess (rc, null, null);
11991 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11992 rc.Report.Error (1913, loc,
11993 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11994 member.GetSignatureForError ());
12000 rc.Report.Error (1914, loc,
12001 "Static field or property `{0}' cannot be assigned in an object initializer",
12002 me.GetSignatureForError ());
12006 me.InstanceExpression = rc.CurrentInitializerVariable;
12014 // A collection initializer expression
12016 class CollectionElementInitializer : Invocation
12018 public class ElementInitializerArgument : Argument
12020 public ElementInitializerArgument (Expression e)
12026 sealed class AddMemberAccess : MemberAccess
12028 public AddMemberAccess (Expression expr, Location loc)
12029 : base (expr, "Add", loc)
12033 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
12035 if (TypeManager.HasElementType (type))
12038 base.Error_TypeDoesNotContainDefinition (ec, type, name);
12042 public CollectionElementInitializer (Expression argument)
12043 : base (null, new Arguments (1))
12045 base.arguments.Add (new ElementInitializerArgument (argument));
12046 this.loc = argument.Location;
12049 public CollectionElementInitializer (List<Expression> arguments, Location loc)
12050 : base (null, new Arguments (arguments.Count))
12052 foreach (Expression e in arguments)
12053 base.arguments.Add (new ElementInitializerArgument (e));
12058 public CollectionElementInitializer (Location loc)
12059 : base (null, null)
12064 public override Expression CreateExpressionTree (ResolveContext ec)
12066 Arguments args = new Arguments (2);
12067 args.Add (new Argument (mg.CreateExpressionTree (ec)));
12069 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
12070 foreach (Argument a in arguments) {
12071 if (a.ArgType == Argument.AType.ExtensionType) {
12072 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
12075 expr_initializers.Add (a.CreateExpressionTree (ec));
12078 args.Add (new Argument (new ArrayCreation (
12079 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
12080 return CreateExpressionFactoryCall (ec, "ElementInit", args);
12083 protected override void CloneTo (CloneContext clonectx, Expression t)
12085 CollectionElementInitializer target = (CollectionElementInitializer) t;
12086 if (arguments != null)
12087 target.arguments = arguments.Clone (clonectx);
12090 protected override Expression DoResolve (ResolveContext ec)
12092 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
12094 return base.DoResolve (ec);
12098 class DictionaryElementInitializer : ElementInitializer
12100 readonly Arguments args;
12102 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
12103 : base (null, initializer, loc)
12105 this.args = arguments;
12108 public override Expression CreateExpressionTree (ResolveContext ec)
12110 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
12114 protected override bool ResolveElement (ResolveContext rc)
12116 var init = rc.CurrentInitializerVariable;
12117 var type = init.Type;
12119 if (type.IsArray) {
12120 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
12124 if (type.IsPointer) {
12125 target = init.MakePointerAccess (rc, type, args);
12129 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
12130 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12131 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
12135 target = new IndexerExpr (indexers, type, init, args, loc);
12141 // A block of object or collection initializers
12143 public class CollectionOrObjectInitializers : ExpressionStatement
12145 IList<Expression> initializers;
12146 bool is_collection_initialization;
12148 public CollectionOrObjectInitializers (Location loc)
12149 : this (new Expression[0], loc)
12153 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12155 this.initializers = initializers;
12159 public IList<Expression> Initializers {
12161 return initializers;
12165 public bool IsEmpty {
12167 return initializers.Count == 0;
12171 public bool IsCollectionInitializer {
12173 return is_collection_initialization;
12177 protected override void CloneTo (CloneContext clonectx, Expression target)
12179 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12181 t.initializers = new List<Expression> (initializers.Count);
12182 foreach (var e in initializers)
12183 t.initializers.Add (e.Clone (clonectx));
12186 public override bool ContainsEmitWithAwait ()
12188 foreach (var e in initializers) {
12189 if (e.ContainsEmitWithAwait ())
12196 public override Expression CreateExpressionTree (ResolveContext ec)
12198 return CreateExpressionTree (ec, false);
12201 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12203 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12204 foreach (Expression e in initializers) {
12205 Expression expr = e.CreateExpressionTree (ec);
12207 expr_initializers.Add (expr);
12211 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12213 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12216 protected override Expression DoResolve (ResolveContext ec)
12218 List<string> element_names = null;
12219 for (int i = 0; i < initializers.Count; ++i) {
12220 Expression initializer = initializers [i];
12221 ElementInitializer element_initializer = initializer as ElementInitializer;
12224 if (element_initializer != null) {
12225 element_names = new List<string> (initializers.Count);
12226 if (!element_initializer.IsDictionaryInitializer)
12227 element_names.Add (element_initializer.Name);
12228 } else if (initializer is CompletingExpression) {
12229 initializer.Resolve (ec);
12230 throw new InternalErrorException ("This line should never be reached");
12232 var t = ec.CurrentInitializerVariable.Type;
12233 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12234 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12235 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12236 "object initializer because type `{1}' does not implement `{2}' interface",
12237 ec.CurrentInitializerVariable.GetSignatureForError (),
12238 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12239 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12242 is_collection_initialization = true;
12245 if (is_collection_initialization != (element_initializer == null)) {
12246 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12247 is_collection_initialization ? "collection initializer" : "object initializer");
12251 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12252 if (element_names.Contains (element_initializer.Name)) {
12253 ec.Report.Error (1912, element_initializer.Location,
12254 "An object initializer includes more than one member `{0}' initialization",
12255 element_initializer.Name);
12257 element_names.Add (element_initializer.Name);
12262 Expression e = initializer.Resolve (ec);
12263 if (e == EmptyExpressionStatement.Instance)
12264 initializers.RemoveAt (i--);
12266 initializers [i] = e;
12269 type = ec.CurrentInitializerVariable.Type;
12270 if (is_collection_initialization) {
12271 if (TypeManager.HasElementType (type)) {
12272 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12273 type.GetSignatureForError ());
12277 eclass = ExprClass.Variable;
12281 public override void Emit (EmitContext ec)
12283 EmitStatement (ec);
12286 public override void EmitStatement (EmitContext ec)
12288 foreach (ExpressionStatement e in initializers) {
12289 // TODO: need location region
12290 ec.Mark (e.Location);
12291 e.EmitStatement (ec);
12295 public override void FlowAnalysis (FlowAnalysisContext fc)
12297 foreach (var initializer in initializers) {
12298 if (initializer != null)
12299 initializer.FlowAnalysis (fc);
12305 // New expression with element/object initializers
12307 public class NewInitialize : New
12310 // This class serves as a proxy for variable initializer target instances.
12311 // A real variable is assigned later when we resolve left side of an
12314 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12316 NewInitialize new_instance;
12318 public InitializerTargetExpression (NewInitialize newInstance)
12320 this.type = newInstance.type;
12321 this.loc = newInstance.loc;
12322 this.eclass = newInstance.eclass;
12323 this.new_instance = newInstance;
12326 public override bool ContainsEmitWithAwait ()
12331 public override Expression CreateExpressionTree (ResolveContext ec)
12333 // Should not be reached
12334 throw new NotSupportedException ("ET");
12337 protected override Expression DoResolve (ResolveContext ec)
12342 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12347 public override void Emit (EmitContext ec)
12349 Expression e = (Expression) new_instance.instance;
12353 public override Expression EmitToField (EmitContext ec)
12355 return (Expression) new_instance.instance;
12358 #region IMemoryLocation Members
12360 public void AddressOf (EmitContext ec, AddressOp mode)
12362 new_instance.instance.AddressOf (ec, mode);
12368 CollectionOrObjectInitializers initializers;
12369 IMemoryLocation instance;
12370 DynamicExpressionStatement dynamic;
12372 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12373 : base (requested_type, arguments, l)
12375 this.initializers = initializers;
12378 public CollectionOrObjectInitializers Initializers {
12380 return initializers;
12384 protected override void CloneTo (CloneContext clonectx, Expression t)
12386 base.CloneTo (clonectx, t);
12388 NewInitialize target = (NewInitialize) t;
12389 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12392 public override bool ContainsEmitWithAwait ()
12394 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12397 public override Expression CreateExpressionTree (ResolveContext ec)
12399 Arguments args = new Arguments (2);
12400 args.Add (new Argument (base.CreateExpressionTree (ec)));
12401 if (!initializers.IsEmpty)
12402 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12404 return CreateExpressionFactoryCall (ec,
12405 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12409 protected override Expression DoResolve (ResolveContext rc)
12411 Expression e = base.DoResolve (rc);
12415 if (type.IsDelegate) {
12416 rc.Report.Error (1958, Initializers.Location,
12417 "Object and collection initializers cannot be used to instantiate a delegate");
12420 Expression previous = rc.CurrentInitializerVariable;
12421 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12422 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12423 initializers.Resolve (rc);
12425 rc.CurrentInitializerVariable = previous;
12427 dynamic = e as DynamicExpressionStatement;
12428 if (dynamic != null)
12434 public override void Emit (EmitContext ec)
12436 if (!CanEmitOptimizedLocalTarget (ec)) {
12437 var fe = ec.GetTemporaryField (type);
12439 if (!Emit (ec, fe))
12448 public override bool Emit (EmitContext ec, IMemoryLocation target)
12451 // Expression is initialized into temporary target then moved
12452 // to real one for atomicity
12454 IMemoryLocation temp_target = target;
12456 LocalTemporary temp = null;
12457 bool by_ref = false;
12458 if (!initializers.IsEmpty) {
12459 temp_target = target as LocalTemporary;
12460 if (temp_target == null)
12461 temp_target = target as StackFieldExpr;
12463 if (temp_target == null) {
12464 var vr = target as VariableReference;
12465 if (vr != null && vr.IsRef) {
12471 if (temp_target == null)
12472 temp_target = temp = new LocalTemporary (type);
12475 bool left_on_stack;
12476 if (dynamic != null) {
12478 left_on_stack = true;
12480 left_on_stack = base.Emit (ec, temp_target);
12483 if (initializers.IsEmpty)
12484 return left_on_stack;
12486 StackFieldExpr sf = null;
12488 // Move a new instance (reference-type) to local temporary variable
12489 if (left_on_stack) {
12491 temp_target = temp = new LocalTemporary (type);
12497 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12499 throw new NotImplementedException ();
12501 sf = ec.GetTemporaryField (type);
12502 sf.AutomaticallyReuse = false;
12503 sf.EmitAssign (ec, temp, false, false);
12506 left_on_stack = false;
12510 instance = temp_target;
12512 initializers.Emit (ec);
12514 ((Expression)temp_target).Emit (ec);
12520 sf.PrepareCleanup (ec);
12525 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12527 return !(method == null && TypeSpec.IsValueType (type) &&
12528 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12529 initializers.ContainsEmitWithAwait ());
12532 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12534 instance = base.EmitAddressOf (ec, Mode);
12536 if (!initializers.IsEmpty)
12537 initializers.Emit (ec);
12542 public override void FlowAnalysis (FlowAnalysisContext fc)
12544 base.FlowAnalysis (fc);
12545 initializers.FlowAnalysis (fc);
12548 public override object Accept (StructuralVisitor visitor)
12550 return visitor.Visit (this);
12554 public class NewAnonymousType : New
12556 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12558 List<AnonymousTypeParameter> parameters;
12559 readonly TypeContainer parent;
12560 AnonymousTypeClass anonymous_type;
12562 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12563 : base (null, null, loc)
12565 this.parameters = parameters;
12566 this.parent = parent;
12569 public List<AnonymousTypeParameter> Parameters {
12571 return this.parameters;
12575 protected override void CloneTo (CloneContext clonectx, Expression target)
12577 if (parameters == null)
12580 NewAnonymousType t = (NewAnonymousType) target;
12581 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12582 foreach (AnonymousTypeParameter atp in parameters)
12583 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12586 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12588 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12592 type = AnonymousTypeClass.Create (parent, parameters, loc);
12596 int errors = ec.Report.Errors;
12597 type.CreateContainer ();
12598 type.DefineContainer ();
12599 type.ExpandBaseInterfaces ();
12601 if ((ec.Report.Errors - errors) == 0) {
12602 parent.Module.AddAnonymousType (type);
12603 type.PrepareEmit ();
12609 public override Expression CreateExpressionTree (ResolveContext ec)
12611 if (parameters == null)
12612 return base.CreateExpressionTree (ec);
12614 var init = new ArrayInitializer (parameters.Count, loc);
12615 foreach (var m in anonymous_type.Members) {
12616 var p = m as Property;
12618 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12621 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12622 foreach (Argument a in arguments)
12623 ctor_args.Add (a.CreateExpressionTree (ec));
12625 Arguments args = new Arguments (3);
12626 args.Add (new Argument (new TypeOfMethod (method, loc)));
12627 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12628 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12630 return CreateExpressionFactoryCall (ec, "New", args);
12633 protected override Expression DoResolve (ResolveContext ec)
12635 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12636 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12640 if (parameters == null) {
12641 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12642 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12643 return base.DoResolve (ec);
12646 bool error = false;
12647 arguments = new Arguments (parameters.Count);
12648 var t_args = new TypeSpec [parameters.Count];
12649 for (int i = 0; i < parameters.Count; ++i) {
12650 Expression e = parameters [i].Resolve (ec);
12656 arguments.Add (new Argument (e));
12657 t_args [i] = e.Type;
12663 anonymous_type = CreateAnonymousType (ec, parameters);
12664 if (anonymous_type == null)
12667 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12668 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12669 eclass = ExprClass.Value;
12673 public override object Accept (StructuralVisitor visitor)
12675 return visitor.Visit (this);
12679 public class AnonymousTypeParameter : ShimExpression
12681 public readonly string Name;
12683 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12684 : base (initializer)
12690 public AnonymousTypeParameter (Parameter parameter)
12691 : base (new SimpleName (parameter.Name, parameter.Location))
12693 this.Name = parameter.Name;
12694 this.loc = parameter.Location;
12697 public override bool Equals (object o)
12699 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12700 return other != null && Name == other.Name;
12703 public override int GetHashCode ()
12705 return Name.GetHashCode ();
12708 protected override Expression DoResolve (ResolveContext ec)
12710 Expression e = expr.Resolve (ec);
12714 if (e.eclass == ExprClass.MethodGroup) {
12715 Error_InvalidInitializer (ec, e.ExprClassName);
12720 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
12721 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12728 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12730 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12731 Name, initializer);
12735 public class CatchFilterExpression : BooleanExpression
12737 public CatchFilterExpression (Expression expr, Location loc)
12744 public class InterpolatedString : Expression
12746 readonly StringLiteral start, end;
12747 List<Expression> interpolations;
12748 Arguments arguments;
12750 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12752 this.start = start;
12754 this.interpolations = interpolations;
12755 loc = start.Location;
12758 protected override void CloneTo (CloneContext clonectx, Expression t)
12760 InterpolatedString target = (InterpolatedString) t;
12762 if (interpolations != null) {
12763 target.interpolations = new List<Expression> ();
12764 foreach (var interpolation in interpolations) {
12765 target.interpolations.Add (interpolation.Clone (clonectx));
12770 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12772 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12773 if (factory == null)
12776 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12777 var res = new Invocation (ma, arguments).Resolve (rc);
12778 if (res != null && res.Type != type)
12779 res = Convert.ExplicitConversion (rc, res, type, loc);
12784 public override bool ContainsEmitWithAwait ()
12786 if (interpolations == null)
12789 foreach (var expr in interpolations) {
12790 if (expr.ContainsEmitWithAwait ())
12797 public override Expression CreateExpressionTree (ResolveContext rc)
12799 var best = ResolveBestFormatOverload (rc);
12803 Expression instance = new NullLiteral (loc);
12804 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12805 return CreateExpressionFactoryCall (rc, "Call", args);
12808 protected override Expression DoResolve (ResolveContext rc)
12812 if (interpolations == null) {
12814 arguments = new Arguments (1);
12816 arguments = new Arguments (interpolations.Count);
12818 var sb = new StringBuilder (start.Value);
12819 for (int i = 0; i < interpolations.Count; ++i) {
12821 sb.Append ('{').Append (i / 2);
12822 var isi = (InterpolatedStringInsert)interpolations [i];
12823 if (isi.Alignment != null) {
12825 var value = isi.ResolveAligment (rc);
12827 sb.Append (value.Value);
12830 if (isi.Format != null) {
12832 sb.Append (isi.Format);
12836 arguments.Add (new Argument (isi.Resolve (rc)));
12838 sb.Append (((StringLiteral)interpolations [i]).Value);
12842 sb.Append (end.Value);
12843 str = sb.ToString ();
12846 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12848 eclass = ExprClass.Value;
12849 type = rc.BuiltinTypes.String;
12853 public override void Emit (EmitContext ec)
12855 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12856 if (interpolations == null) {
12857 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12858 if (str != start.Value)
12859 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12866 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12870 var ca = new CallEmitter ();
12871 ca.Emit (ec, best, arguments, loc);
12874 public override void FlowAnalysis (FlowAnalysisContext fc)
12876 if (interpolations != null) {
12877 foreach (var expr in interpolations) {
12878 expr.FlowAnalysis (fc);
12883 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12885 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12886 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12887 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12891 public class InterpolatedStringInsert : CompositeExpression
12893 public InterpolatedStringInsert (Expression expr)
12898 public Expression Alignment { get; set; }
12899 public string Format { get; set; }
12901 protected override void CloneTo (CloneContext clonectx, Expression t)
12903 var target = (InterpolatedStringInsert)t;
12904 target.expr = expr.Clone (clonectx);
12905 if (Alignment != null)
12906 target.Alignment = Alignment.Clone (clonectx);
12909 protected override Expression DoResolve (ResolveContext rc)
12911 var expr = base.DoResolve (rc);
12916 // For better error reporting, assumes the built-in implementation uses object
12919 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12922 public override void FlowAnalysis (FlowAnalysisContext fc)
12924 Child.FlowAnalysis (fc);
12927 public int? ResolveAligment (ResolveContext rc)
12929 var c = Alignment.ResolveLabelConstant (rc);
12933 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12937 var value = (int) c.GetValueAsLong ();
12938 if (value > 32767 || value < -32767) {
12939 rc.Report.Warning (8094, 1, Alignment.Location,
12940 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12947 class ThrowExpression : ExpressionStatement
12951 public ThrowExpression (Expression expr, Location loc)
12957 protected override void CloneTo (CloneContext clonectx, Expression t)
12959 var target = (ThrowExpression)t;
12960 target.expr = expr.Clone (clonectx);
12963 public override bool ContainsEmitWithAwait ()
12965 return expr.ContainsEmitWithAwait ();
12968 public override Expression CreateExpressionTree (ResolveContext rc)
12970 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12974 protected override Expression DoResolve (ResolveContext rc)
12976 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12981 expr = Throw.ConvertType (rc, expr);
12983 eclass = ExprClass.Value;
12984 type = InternalType.ThrowExpr;
12988 public override void Emit (EmitContext ec)
12990 EmitStatement (ec);
12993 public override void EmitStatement (EmitContext ec)
12997 ec.Emit (OpCodes.Throw);
13000 public override void FlowAnalysis (FlowAnalysisContext fc)
13002 expr.FlowAnalysis (fc);
13005 public override Reachability MarkReachable (Reachability rc)
13007 return Reachability.CreateUnreachable ();
13011 class ReferenceExpression : CompositeExpression
13013 public ReferenceExpression (Expression expr, Location loc)
13019 static bool CanBeByRef (Expression expr)
13021 if (expr is IAssignMethod)
13024 var invocation = expr as Invocation;
13025 if (invocation?.Type.Kind == MemberKind.ByRef)
13031 public override Expression CreateExpressionTree (ResolveContext rc)
13033 throw new NotSupportedException ("ET");
13036 protected override Expression DoResolve (ResolveContext rc)
13038 var res = expr.DoResolveLValue (rc, EmptyExpression.OutAccess);
13039 if (res == null || !CanBeByRef (res)) {
13040 if (res?.Type != InternalType.ErrorType)
13041 rc.Report.Error (8156, expr.Location, "An expression cannot be used in this context because it may not be returned by reference");
13042 return ErrorExpression.Instance;
13046 var type_container = type as ReferenceContainer;
13047 if (type_container != null)
13048 type = type_container.Element;
13051 eclass = ExprClass.Value;
13055 public override void Emit (EmitContext ec)
13057 var ml = expr as IMemoryLocation;
13059 ml.AddressOf (ec, AddressOp.LoadStore);
13064 public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl)
13066 rc.Report.Error (8173, loc, "The expression must be of type `{0}' because it is being assigned by reference", target.GetSignatureForError ());
13070 class ByRefDereference : CompositeExpression, IMemoryLocation, IAssignMethod
13073 LocalTemporary temporary;
13075 private ByRefDereference (Expression expr)
13080 public static Expression Create (Expression expr)
13082 var rc = expr.Type as ReferenceContainer;
13086 return new ByRefDereference (expr) {
13091 public void AddressOf (EmitContext ec, AddressOp mode)
13096 public void Emit (EmitContext ec, bool leave_copy)
13100 ec.Emit (OpCodes.Dup);
13101 temporary = new LocalTemporary (type);
13102 temporary.Store (ec);
13106 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
13108 prepared = isCompound;
13113 ec.Emit (OpCodes.Dup);
13117 throw new NotImplementedException ("leave_copy");
13120 ec.EmitStoreFromPtr (type);
13122 if (temporary != null) {
13123 temporary.Emit (ec);
13124 temporary.Release (ec);
13128 protected override Expression DoResolve (ResolveContext rc)
13130 eclass = ExprClass.Variable;
13134 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
13136 return DoResolve (rc);
13139 public override void Emit (EmitContext ec)
13144 ec.EmitLoadFromPtr (type);
13147 public override object Accept (StructuralVisitor visitor)
13149 return visitor.Visit (this);