2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
721 if (ec.CurrentIterator != null) {
722 UnsafeInsideIteratorError (ec, loc);
723 } else if (!ec.IsUnsafe) {
724 UnsafeError (ec, loc);
727 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
728 if (Expr == null || Expr.eclass != ExprClass.Variable) {
729 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
733 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
737 IVariableReference vr = Expr as IVariableReference;
740 is_fixed = vr.IsFixed;
741 vr.SetHasAddressTaken ();
743 if (vr.IsHoisted && ec.CurrentIterator == null) {
744 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
747 IFixedExpression fe = Expr as IFixedExpression;
748 is_fixed = fe != null && fe.IsFixed;
751 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
752 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
755 type = PointerContainer.MakeType (ec.Module, Expr.Type);
756 eclass = ExprClass.Value;
760 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
762 expr = DoNumericPromotion (rc, Oper, expr);
763 TypeSpec expr_type = expr.Type;
764 foreach (TypeSpec t in predefined) {
772 // Perform user-operator overload resolution
774 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
776 CSharp.Operator.OpType op_type;
778 case Operator.LogicalNot:
779 op_type = CSharp.Operator.OpType.LogicalNot; break;
780 case Operator.OnesComplement:
781 op_type = CSharp.Operator.OpType.OnesComplement; break;
782 case Operator.UnaryNegation:
783 op_type = CSharp.Operator.OpType.UnaryNegation; break;
784 case Operator.UnaryPlus:
785 op_type = CSharp.Operator.OpType.UnaryPlus; break;
787 throw new InternalErrorException (Oper.ToString ());
790 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
794 Arguments args = new Arguments (1);
795 args.Add (new Argument (expr));
797 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
798 var oper = res.ResolveOperator (ec, ref args);
803 Expr = args [0].Expr;
804 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
808 // Unary user type overload resolution
810 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
812 Expression best_expr = ResolveUserOperator (ec, expr);
813 if (best_expr != null)
816 foreach (TypeSpec t in predefined) {
817 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
818 if (oper_expr == null)
821 if (oper_expr == ErrorExpression.Instance)
825 // decimal type is predefined but has user-operators
827 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
828 oper_expr = ResolveUserType (ec, oper_expr, predefined);
830 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
832 if (oper_expr == null)
835 if (best_expr == null) {
836 best_expr = oper_expr;
840 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
842 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
843 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
845 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
852 best_expr = oper_expr;
855 if (best_expr == null)
859 // HACK: Decimal user-operator is included in standard operators
861 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
865 type = best_expr.Type;
869 protected override void CloneTo (CloneContext clonectx, Expression t)
871 Unary target = (Unary) t;
873 target.Expr = Expr.Clone (clonectx);
876 public override object Accept (StructuralVisitor visitor)
878 return visitor.Visit (this);
884 // Unary operators are turned into Indirection expressions
885 // after semantic analysis (this is so we can take the address
886 // of an indirection).
888 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
890 LocalTemporary temporary;
893 public Indirection (Expression expr, Location l)
899 public Expression Expr {
905 public bool IsFixed {
909 public override Location StartLocation {
911 return expr.StartLocation;
915 protected override void CloneTo (CloneContext clonectx, Expression t)
917 Indirection target = (Indirection) t;
918 target.expr = expr.Clone (clonectx);
921 public override bool ContainsEmitWithAwait ()
923 throw new NotImplementedException ();
926 public override Expression CreateExpressionTree (ResolveContext ec)
928 Error_PointerInsideExpressionTree (ec);
932 public override void Emit (EmitContext ec)
937 ec.EmitLoadFromPtr (Type);
940 public void Emit (EmitContext ec, bool leave_copy)
944 ec.Emit (OpCodes.Dup);
945 temporary = new LocalTemporary (expr.Type);
946 temporary.Store (ec);
950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
952 prepared = isCompound;
957 ec.Emit (OpCodes.Dup);
961 ec.Emit (OpCodes.Dup);
962 temporary = new LocalTemporary (source.Type);
963 temporary.Store (ec);
966 ec.EmitStoreFromPtr (type);
968 if (temporary != null) {
970 temporary.Release (ec);
974 public void AddressOf (EmitContext ec, AddressOp Mode)
979 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
981 return DoResolve (ec);
984 protected override Expression DoResolve (ResolveContext ec)
986 expr = expr.Resolve (ec);
990 if (ec.CurrentIterator != null) {
991 UnsafeInsideIteratorError (ec, loc);
992 } else if (!ec.IsUnsafe) {
993 UnsafeError (ec, loc);
996 var pc = expr.Type as PointerContainer;
999 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1005 if (type.Kind == MemberKind.Void) {
1006 Error_VoidPointerOperation (ec);
1010 eclass = ExprClass.Variable;
1014 public override object Accept (StructuralVisitor visitor)
1016 return visitor.Visit (this);
1021 /// Unary Mutator expressions (pre and post ++ and --)
1025 /// UnaryMutator implements ++ and -- expressions. It derives from
1026 /// ExpressionStatement becuase the pre/post increment/decrement
1027 /// operators can be used in a statement context.
1029 /// FIXME: Idea, we could split this up in two classes, one simpler
1030 /// for the common case, and one with the extra fields for more complex
1031 /// classes (indexers require temporary access; overloaded require method)
1034 public class UnaryMutator : ExpressionStatement
1036 class DynamicPostMutator : Expression, IAssignMethod
1038 LocalTemporary temp;
1041 public DynamicPostMutator (Expression expr)
1044 this.type = expr.Type;
1045 this.loc = expr.Location;
1048 public override Expression CreateExpressionTree (ResolveContext ec)
1050 throw new NotImplementedException ("ET");
1053 protected override Expression DoResolve (ResolveContext rc)
1055 eclass = expr.eclass;
1059 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1061 expr.DoResolveLValue (ec, right_side);
1062 return DoResolve (ec);
1065 public override void Emit (EmitContext ec)
1070 public void Emit (EmitContext ec, bool leave_copy)
1072 throw new NotImplementedException ();
1076 // Emits target assignment using unmodified source value
1078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1081 // Allocate temporary variable to keep original value before it's modified
1083 temp = new LocalTemporary (type);
1087 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1098 public enum Mode : byte {
1105 PreDecrement = IsDecrement,
1106 PostIncrement = IsPost,
1107 PostDecrement = IsPost | IsDecrement
1111 bool is_expr, recurse;
1113 protected Expression expr;
1115 // Holds the real operation
1116 Expression operation;
1118 public UnaryMutator (Mode m, Expression e, Location loc)
1125 public Mode UnaryMutatorMode {
1131 public Expression Expr {
1137 public override Location StartLocation {
1139 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1143 public override bool ContainsEmitWithAwait ()
1145 return expr.ContainsEmitWithAwait ();
1148 public override Expression CreateExpressionTree (ResolveContext ec)
1150 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1153 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1156 // Predefined ++ and -- operators exist for the following types:
1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1159 return new TypeSpec[] {
1175 protected override Expression DoResolve (ResolveContext ec)
1177 expr = expr.Resolve (ec);
1179 if (expr == null || expr.Type == InternalType.ErrorType)
1182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 // Handle postfix unary operators using local
1185 // temporary variable
1187 if ((mode & Mode.IsPost) != 0)
1188 expr = new DynamicPostMutator (expr);
1190 Arguments args = new Arguments (1);
1191 args.Add (new Argument (expr));
1192 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1195 if (expr.Type.IsNullableType)
1196 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1198 return DoResolveOperation (ec);
1201 protected Expression DoResolveOperation (ResolveContext ec)
1203 eclass = ExprClass.Value;
1206 if (expr is RuntimeValueExpression) {
1209 // Use itself at the top of the stack
1210 operation = new EmptyExpression (type);
1214 // The operand of the prefix/postfix increment decrement operators
1215 // should be an expression that is classified as a variable,
1216 // a property access or an indexer access
1218 // TODO: Move to parser, expr is ATypeNameExpression
1219 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1220 expr = expr.ResolveLValue (ec, expr);
1222 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1226 // Step 1: Try to find a user operator, it has priority over predefined ones
1228 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1229 var methods = MemberCache.GetUserOperator (type, user_op, false);
1231 if (methods != null) {
1232 Arguments args = new Arguments (1);
1233 args.Add (new Argument (expr));
1235 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1236 var method = res.ResolveOperator (ec, ref args);
1240 args[0].Expr = operation;
1241 operation = new UserOperatorCall (method, args, null, loc);
1242 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1247 // Step 2: Try predefined types
1250 Expression source = null;
1251 bool primitive_type;
1254 // Predefined without user conversion first for speed-up
1256 // Predefined ++ and -- operators exist for the following types:
1257 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1259 switch (type.BuiltinType) {
1260 case BuiltinTypeSpec.Type.Byte:
1261 case BuiltinTypeSpec.Type.SByte:
1262 case BuiltinTypeSpec.Type.Short:
1263 case BuiltinTypeSpec.Type.UShort:
1264 case BuiltinTypeSpec.Type.Int:
1265 case BuiltinTypeSpec.Type.UInt:
1266 case BuiltinTypeSpec.Type.Long:
1267 case BuiltinTypeSpec.Type.ULong:
1268 case BuiltinTypeSpec.Type.Char:
1269 case BuiltinTypeSpec.Type.Float:
1270 case BuiltinTypeSpec.Type.Double:
1271 case BuiltinTypeSpec.Type.Decimal:
1273 primitive_type = true;
1276 primitive_type = false;
1278 // ++/-- on pointer variables of all types except void*
1279 if (type.IsPointer) {
1280 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1281 Error_VoidPointerOperation (ec);
1287 Expression best_source = null;
1288 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1289 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1291 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1295 if (best_source == null) {
1296 best_source = source;
1300 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1305 best_source = source;
1309 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1313 source = best_source;
1316 // ++/-- on enum types
1317 if (source == null && type.IsEnum)
1320 if (source == null) {
1321 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1328 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1329 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1330 operation = new Binary (op, source, one);
1331 operation = operation.Resolve (ec);
1332 if (operation == null)
1333 throw new NotImplementedException ("should not be reached");
1335 if (operation.Type != type) {
1337 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1339 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1345 void EmitCode (EmitContext ec, bool is_expr)
1348 this.is_expr = is_expr;
1349 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1352 public override void Emit (EmitContext ec)
1355 // We use recurse to allow ourselfs to be the source
1356 // of an assignment. This little hack prevents us from
1357 // having to allocate another expression
1360 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1368 EmitCode (ec, true);
1371 protected virtual void EmitOperation (EmitContext ec)
1373 operation.Emit (ec);
1376 public override void EmitStatement (EmitContext ec)
1378 EmitCode (ec, false);
1381 public override void FlowAnalysis (FlowAnalysisContext fc)
1383 expr.FlowAnalysis (fc);
1387 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1389 string GetOperatorExpressionTypeName ()
1391 return IsDecrement ? "Decrement" : "Increment";
1395 get { return (mode & Mode.IsDecrement) != 0; }
1399 public override SLE.Expression MakeExpression (BuilderContext ctx)
1401 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1402 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1403 return SLE.Expression.Assign (target, source);
1406 public static string OperName (Mode oper)
1408 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1411 protected override void CloneTo (CloneContext clonectx, Expression t)
1413 UnaryMutator target = (UnaryMutator) t;
1415 target.expr = expr.Clone (clonectx);
1418 public override object Accept (StructuralVisitor visitor)
1420 return visitor.Visit (this);
1426 // Base class for the `is' and `as' operators
1428 public abstract class Probe : Expression
1430 public Expression ProbeType;
1431 protected Expression expr;
1432 protected TypeSpec probe_type_expr;
1434 protected Probe (Expression expr, Expression probe_type, Location l)
1436 ProbeType = probe_type;
1441 public Expression Expr {
1447 public override bool ContainsEmitWithAwait ()
1449 return expr.ContainsEmitWithAwait ();
1452 protected Expression ResolveCommon (ResolveContext rc)
1454 expr = expr.Resolve (rc);
1458 ResolveProbeType (rc);
1459 if (probe_type_expr == null)
1462 if (probe_type_expr.IsStatic) {
1463 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1464 probe_type_expr.GetSignatureForError ());
1468 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1469 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1474 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1475 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1483 protected virtual void ResolveProbeType (ResolveContext rc)
1485 probe_type_expr = ProbeType.ResolveAsType (rc);
1488 public override void EmitSideEffect (EmitContext ec)
1490 expr.EmitSideEffect (ec);
1493 public override void EmitPrepare (EmitContext ec)
1495 expr.EmitPrepare (ec);
1498 public override void FlowAnalysis (FlowAnalysisContext fc)
1500 expr.FlowAnalysis (fc);
1503 public override bool HasConditionalAccess ()
1505 return expr.HasConditionalAccess ();
1508 protected abstract string OperatorName { get; }
1510 protected override void CloneTo (CloneContext clonectx, Expression t)
1512 Probe target = (Probe) t;
1514 target.expr = expr.Clone (clonectx);
1515 target.ProbeType = ProbeType.Clone (clonectx);
1521 /// Implementation of the `is' operator.
1523 public class Is : Probe
1525 Nullable.Unwrap expr_unwrap;
1526 MethodSpec number_mg;
1527 Arguments number_args;
1529 public Is (Expression expr, Expression probe_type, Location l)
1530 : base (expr, probe_type, l)
1534 protected override string OperatorName {
1535 get { return "is"; }
1538 public LocalVariable Variable { get; set; }
1540 public override Expression CreateExpressionTree (ResolveContext ec)
1542 if (Variable != null)
1543 ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
1545 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1546 expr.CreateExpressionTree (ec),
1547 new TypeOf (probe_type_expr, loc));
1549 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1552 Expression CreateConstantResult (ResolveContext rc, bool result)
1555 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1556 probe_type_expr.GetSignatureForError ());
1558 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1559 probe_type_expr.GetSignatureForError ());
1561 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1562 return expr.IsSideEffectFree ?
1563 ReducedExpression.Create (c, this) :
1564 new SideEffectConstant (c, this, loc);
1567 public override void Emit (EmitContext ec)
1569 if (probe_type_expr == null) {
1570 if (ProbeType is WildcardPattern) {
1571 expr.EmitSideEffect (ec);
1572 ProbeType.Emit (ec);
1574 EmitPatternMatch (ec);
1581 if (expr_unwrap == null) {
1583 ec.Emit (OpCodes.Cgt_Un);
1587 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1589 if (probe_type_expr == null) {
1590 EmitPatternMatch (ec);
1595 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1598 public override void EmitPrepare (EmitContext ec)
1600 base.EmitPrepare (ec);
1602 if (Variable != null)
1603 Variable.CreateBuilder (ec);
1606 void EmitPatternMatch (EmitContext ec)
1608 var no_match = ec.DefineLabel ();
1609 var end = ec.DefineLabel ();
1611 if (expr_unwrap != null) {
1612 expr_unwrap.EmitCheck (ec);
1614 if (ProbeType.IsNull) {
1616 ec.Emit (OpCodes.Ceq);
1620 ec.Emit (OpCodes.Brfalse_S, no_match);
1621 expr_unwrap.Emit (ec);
1622 ProbeType.Emit (ec);
1623 ec.Emit (OpCodes.Ceq);
1624 ec.Emit (OpCodes.Br_S, end);
1625 ec.MarkLabel (no_match);
1631 if (number_args != null && number_args.Count == 3) {
1632 var ce = new CallEmitter ();
1633 ce.Emit (ec, number_mg, number_args, loc);
1637 var probe_type = ProbeType.Type;
1640 ec.Emit (OpCodes.Isinst, probe_type);
1641 ec.Emit (OpCodes.Dup);
1642 ec.Emit (OpCodes.Brfalse, no_match);
1644 bool complex_pattern = ProbeType is ComplexPatternExpression;
1645 Label prev = ec.RecursivePatternLabel;
1646 if (complex_pattern)
1647 ec.RecursivePatternLabel = ec.DefineLabel ();
1649 if (number_mg != null) {
1650 var ce = new CallEmitter ();
1651 ce.Emit (ec, number_mg, number_args, loc);
1653 if (TypeSpec.IsValueType (probe_type))
1654 ec.Emit (OpCodes.Unbox_Any, probe_type);
1656 ProbeType.Emit (ec);
1657 if (complex_pattern) {
1660 ec.Emit (OpCodes.Ceq);
1663 ec.Emit (OpCodes.Br_S, end);
1664 ec.MarkLabel (no_match);
1666 ec.Emit (OpCodes.Pop);
1668 if (complex_pattern)
1669 ec.MarkLabel (ec.RecursivePatternLabel);
1671 ec.RecursivePatternLabel = prev;
1677 void EmitLoad (EmitContext ec)
1679 Label no_value_label = new Label ();
1681 if (expr_unwrap != null) {
1682 expr_unwrap.EmitCheck (ec);
1684 if (Variable == null)
1687 ec.Emit (OpCodes.Dup);
1688 no_value_label = ec.DefineLabel ();
1689 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1691 if (Variable.HoistedVariant != null)
1694 expr_unwrap.Emit (ec);
1696 if (Variable?.HoistedVariant != null)
1701 // Only to make verifier happy
1702 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1703 ec.Emit (OpCodes.Box, expr.Type);
1705 ec.Emit (OpCodes.Isinst, probe_type_expr);
1708 if (Variable != null) {
1709 bool value_on_stack;
1710 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1711 ec.Emit (OpCodes.Dup);
1712 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1713 value_on_stack = true;
1715 value_on_stack = false;
1718 if (Variable.HoistedVariant != null) {
1719 Variable.HoistedVariant.EmitAssignFromStack (ec);
1721 if (expr_unwrap != null) {
1722 ec.MarkLabel (no_value_label);
1723 } else if (!value_on_stack) {
1724 Variable.HoistedVariant.Emit (ec);
1728 // It's ok to have variable builder created out of order. It simplifies emit
1729 // of statements like while (condition) { }
1731 if (!Variable.Created)
1732 Variable.CreateBuilder (ec);
1734 Variable.EmitAssign (ec);
1736 if (expr_unwrap != null) {
1737 ec.MarkLabel (no_value_label);
1738 } else if (!value_on_stack) {
1745 protected override Expression DoResolve (ResolveContext rc)
1747 if (ResolveCommon (rc) == null)
1750 type = rc.BuiltinTypes.Bool;
1751 eclass = ExprClass.Value;
1753 if (probe_type_expr == null)
1754 return ResolveMatchingExpression (rc);
1756 var res = ResolveResultExpression (rc);
1757 if (Variable != null) {
1758 if (res is Constant)
1759 throw new NotImplementedException ("constant in type pattern matching");
1761 Variable.Type = probe_type_expr;
1762 var bc = rc as BlockContext;
1764 Variable.PrepareAssignmentAnalysis (bc);
1770 public override void FlowAnalysis (FlowAnalysisContext fc)
1772 base.FlowAnalysis (fc);
1774 if (Variable != null)
1775 fc.SetVariableAssigned (Variable.VariableInfo, true);
1778 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
1780 if (Variable == null) {
1781 base.FlowAnalysisConditional (fc);
1785 expr.FlowAnalysis (fc);
1787 fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
1788 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1790 fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
1793 protected override void ResolveProbeType (ResolveContext rc)
1795 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1796 if (ProbeType is PatternExpression) {
1797 ProbeType.Resolve (rc);
1802 // Have to use session recording because we don't have reliable type probing
1803 // mechanism (similar issue as in attributes resolving)
1805 // TODO: This is still wrong because ResolveAsType can be destructive
1807 var type_printer = new SessionReportPrinter ();
1808 var prev_recorder = rc.Report.SetPrinter (type_printer);
1810 probe_type_expr = ProbeType.ResolveAsType (rc);
1811 type_printer.EndSession ();
1813 if (probe_type_expr != null) {
1814 type_printer.Merge (rc.Report.Printer);
1815 rc.Report.SetPrinter (prev_recorder);
1819 var vexpr = ProbeType as VarExpr;
1820 if (vexpr != null && vexpr.InferType (rc, expr)) {
1821 probe_type_expr = vexpr.Type;
1822 rc.Report.SetPrinter (prev_recorder);
1826 var expr_printer = new SessionReportPrinter ();
1827 rc.Report.SetPrinter (expr_printer);
1828 ProbeType = ProbeType.Resolve (rc);
1829 expr_printer.EndSession ();
1831 if (ProbeType != null) {
1832 expr_printer.Merge (rc.Report.Printer);
1834 type_printer.Merge (rc.Report.Printer);
1837 rc.Report.SetPrinter (prev_recorder);
1841 base.ResolveProbeType (rc);
1844 Expression ResolveMatchingExpression (ResolveContext rc)
1846 var mc = ProbeType as Constant;
1848 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1849 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1854 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1856 var c = Expr as Constant;
1858 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1863 if (Expr.Type.IsNullableType) {
1864 expr_unwrap = new Nullable.Unwrap (Expr);
1865 expr_unwrap.Resolve (rc);
1866 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1867 } else if (ProbeType.Type == Expr.Type) {
1868 // TODO: Better error handling
1869 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1870 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1871 var helper = rc.Module.CreatePatterMatchingHelper ();
1872 number_mg = helper.NumberMatcher.Spec;
1875 // There are actually 3 arguments but the first one is already on the stack
1877 number_args = new Arguments (3);
1878 if (!ProbeType.Type.IsEnum)
1879 number_args.Add (new Argument (Expr));
1881 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1882 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1888 if (ProbeType is PatternExpression) {
1889 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1890 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1896 // TODO: Better error message
1897 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1901 Expression ResolveResultExpression (ResolveContext ec)
1903 if (Variable != null) {
1904 if (expr is NullLiteral) {
1905 ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
1909 CheckExpressionVariable (ec);
1912 TypeSpec d = expr.Type;
1913 bool d_is_nullable = false;
1916 // If E is a method group or the null literal, or if the type of E is a reference
1917 // type or a nullable type and the value of E is null, the result is false
1920 return CreateConstantResult (ec, false);
1922 if (d.IsNullableType) {
1923 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1924 if (!ut.IsGenericParameter) {
1926 d_is_nullable = true;
1930 TypeSpec t = probe_type_expr;
1931 bool t_is_nullable = false;
1932 if (t.IsNullableType) {
1933 if (Variable != null) {
1934 ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
1935 t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
1938 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1939 if (!ut.IsGenericParameter) {
1941 t_is_nullable = true;
1948 // D and T are the same value types but D can be null
1950 if (d_is_nullable && !t_is_nullable) {
1951 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1956 // The result is true if D and T are the same value types
1958 return CreateConstantResult (ec, true);
1961 var tp = d as TypeParameterSpec;
1963 return ResolveGenericParameter (ec, t, tp);
1966 // An unboxing conversion exists
1968 if (Convert.ExplicitReferenceConversionExists (d, t))
1972 // open generic type
1974 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1977 var tps = t as TypeParameterSpec;
1979 return ResolveGenericParameter (ec, d, tps);
1981 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1982 if (Variable != null) {
1983 ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
1985 ec.Report.Warning (1981, 3, loc,
1986 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1987 OperatorName, t.GetSignatureForError ());
1991 if (TypeManager.IsGenericParameter (d))
1992 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1994 if (TypeSpec.IsValueType (d)) {
1995 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1996 if (d_is_nullable && !t_is_nullable) {
1997 expr_unwrap = Nullable.Unwrap.Create (expr, false);
2001 return CreateConstantResult (ec, true);
2004 if (Convert.ImplicitReferenceConversionExists (d, t)) {
2005 var c = expr as Constant;
2007 return CreateConstantResult (ec, !c.IsNull);
2010 // Do not optimize for imported type or dynamic type
2012 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
2013 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
2017 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
2021 // Turn is check into simple null check for implicitly convertible reference types
2023 return ReducedExpression.Create (
2024 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
2028 if (Convert.ExplicitReferenceConversionExists (d, t))
2032 // open generic type
2034 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
2039 return CreateConstantResult (ec, false);
2042 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
2044 if (t.IsReferenceType) {
2046 return CreateConstantResult (ec, false);
2049 if (expr.Type.IsGenericParameter) {
2050 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2051 return CreateConstantResult (ec, true);
2053 expr = new BoxedCast (expr, d);
2059 public override object Accept (StructuralVisitor visitor)
2061 return visitor.Visit (this);
2065 class WildcardPattern : PatternExpression
2067 public WildcardPattern (Location loc)
2072 protected override Expression DoResolve (ResolveContext rc)
2074 eclass = ExprClass.Value;
2075 type = rc.BuiltinTypes.Object;
2079 public override void Emit (EmitContext ec)
2085 class RecursivePattern : ComplexPatternExpression
2087 MethodGroupExpr operator_mg;
2088 Arguments operator_args;
2090 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2091 : base (typeExpresion, loc)
2093 Arguments = arguments;
2096 public Arguments Arguments { get; private set; }
2098 protected override Expression DoResolve (ResolveContext rc)
2100 type = TypeExpression.ResolveAsType (rc);
2104 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2105 if (operators == null) {
2106 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2110 var ops = FindMatchingOverloads (operators);
2112 // TODO: better error message
2113 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2118 Arguments.Resolve (rc, out dynamic_args);
2120 throw new NotImplementedException ("dynamic argument");
2122 var op = FindBestOverload (rc, ops);
2124 // TODO: better error message
2125 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2129 var op_types = op.Parameters.Types;
2130 operator_args = new Arguments (op_types.Length);
2131 operator_args.Add (new Argument (new EmptyExpression (type)));
2133 for (int i = 0; i < Arguments.Count; ++i) {
2134 // TODO: Needs releasing optimization
2135 var lt = new LocalTemporary (op_types [i + 1]);
2136 operator_args.Add (new Argument (lt, Argument.AType.Out));
2138 if (comparisons == null)
2139 comparisons = new Expression[Arguments.Count];
2144 var arg = Arguments [i];
2145 var named = arg as NamedArgument;
2146 if (named != null) {
2147 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2148 expr = Arguments [arg_comp_index].Expr;
2154 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2157 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2159 eclass = ExprClass.Value;
2163 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2165 int arg_count = Arguments.Count + 1;
2166 List<MethodSpec> best = null;
2167 foreach (MethodSpec method in members) {
2168 var pm = method.Parameters;
2169 if (pm.Count != arg_count)
2172 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2174 for (int ii = 1; ii < pm.Count; ++ii) {
2175 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2185 best = new List<MethodSpec> ();
2193 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2195 for (int ii = 0; ii < Arguments.Count; ++ii) {
2196 var arg = Arguments [ii];
2197 var expr = arg.Expr;
2198 if (expr is WildcardPattern)
2201 var na = arg as NamedArgument;
2202 for (int i = 0; i < methods.Count; ++i) {
2203 var pd = methods [i].Parameters;
2207 index = pd.GetParameterIndexByName (na.Name);
2209 methods.RemoveAt (i--);
2216 var m = pd.Types [index];
2217 if (!Convert.ImplicitConversionExists (rc, expr, m))
2218 methods.RemoveAt (i--);
2222 if (methods.Count != 1)
2228 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2230 operator_mg.EmitCall (ec, operator_args, false);
2231 ec.Emit (OpCodes.Brfalse, target);
2233 base.EmitBranchable (ec, target, on_true);
2236 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2238 if (expr is WildcardPattern)
2239 return new EmptyExpression (expr.Type);
2241 var recursive = expr as RecursivePattern;
2242 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2246 if (recursive != null) {
2247 recursive.SetParentInstance (lt);
2251 // TODO: Better error handling
2252 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2255 public void SetParentInstance (Expression instance)
2257 operator_args [0] = new Argument (instance);
2261 class PropertyPattern : ComplexPatternExpression
2263 LocalTemporary instance;
2265 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2266 : base (typeExpresion, loc)
2271 public List<PropertyPatternMember> Members { get; private set; }
2273 protected override Expression DoResolve (ResolveContext rc)
2275 type = TypeExpression.ResolveAsType (rc);
2279 comparisons = new Expression[Members.Count];
2281 // TODO: optimize when source is VariableReference, it'd save dup+pop
2282 instance = new LocalTemporary (type);
2284 for (int i = 0; i < Members.Count; i++) {
2285 var lookup = Members [i];
2287 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2288 if (member == null) {
2289 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2290 if (member != null) {
2291 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2296 if (member == null) {
2297 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2301 var pe = member as PropertyExpr;
2302 if (pe == null || member is FieldExpr) {
2303 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2307 // TODO: Obsolete checks
2308 // TODO: check accessibility
2309 if (pe != null && !pe.PropertyInfo.HasGet) {
2310 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2314 var expr = lookup.Expr.Resolve (rc);
2318 var me = (MemberExpr)member;
2319 me.InstanceExpression = instance;
2321 comparisons [i] = ResolveComparison (rc, expr, me);
2324 eclass = ExprClass.Value;
2328 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2330 if (expr is WildcardPattern)
2331 return new EmptyExpression (expr.Type);
2333 return new Is (instance, expr, expr.Location).Resolve (rc);
2336 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2338 instance.Store (ec);
2340 base.EmitBranchable (ec, target, on_true);
2344 class PropertyPatternMember
2346 public PropertyPatternMember (string name, Expression expr, Location loc)
2353 public string Name { get; private set; }
2354 public Expression Expr { get; private set; }
2355 public Location Location { get; private set; }
2358 abstract class PatternExpression : Expression
2360 protected PatternExpression (Location loc)
2365 public override Expression CreateExpressionTree (ResolveContext ec)
2367 throw new NotImplementedException ();
2371 abstract class ComplexPatternExpression : PatternExpression
2373 protected Expression[] comparisons;
2375 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2378 TypeExpression = typeExpresion;
2381 public ATypeNameExpression TypeExpression { get; private set; }
2383 public override void Emit (EmitContext ec)
2385 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2388 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2390 if (comparisons != null) {
2391 foreach (var comp in comparisons) {
2392 comp.EmitBranchable (ec, target, false);
2399 /// Implementation of the `as' operator.
2401 public class As : Probe {
2403 public As (Expression expr, Expression probe_type, Location l)
2404 : base (expr, probe_type, l)
2408 protected override string OperatorName {
2409 get { return "as"; }
2412 public override Expression CreateExpressionTree (ResolveContext ec)
2414 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2415 expr.CreateExpressionTree (ec),
2416 new TypeOf (probe_type_expr, loc));
2418 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2421 public override void Emit (EmitContext ec)
2425 ec.Emit (OpCodes.Isinst, type);
2427 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2428 ec.Emit (OpCodes.Unbox_Any, type);
2431 protected override Expression DoResolve (ResolveContext ec)
2433 if (ResolveCommon (ec) == null)
2436 type = probe_type_expr;
2437 eclass = ExprClass.Value;
2438 TypeSpec etype = expr.Type;
2440 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) {
2441 ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type");
2442 type = InternalType.ErrorType;
2447 type = InternalType.ErrorType;
2451 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2452 if (TypeManager.IsGenericParameter (type)) {
2453 ec.Report.Error (413, loc,
2454 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2455 probe_type_expr.GetSignatureForError ());
2457 ec.Report.Error (77, loc,
2458 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2459 type.GetSignatureForError ());
2464 if (expr.IsNull && type.IsNullableType) {
2465 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2468 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2469 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2473 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2475 e = EmptyCast.Create (e, type);
2476 return ReducedExpression.Create (e, this).Resolve (ec);
2479 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2480 if (TypeManager.IsGenericParameter (etype))
2481 expr = new BoxedCast (expr, etype);
2486 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2487 expr = new BoxedCast (expr, etype);
2491 if (etype != InternalType.ErrorType) {
2492 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2493 etype.GetSignatureForError (), type.GetSignatureForError ());
2499 public override object Accept (StructuralVisitor visitor)
2501 return visitor.Visit (this);
2506 // This represents a typecast in the source language.
2508 public class Cast : ShimExpression {
2509 Expression target_type;
2511 public Cast (Expression cast_type, Expression expr, Location loc)
2514 this.target_type = cast_type;
2518 public Expression TargetType {
2519 get { return target_type; }
2522 protected override Expression DoResolve (ResolveContext ec)
2524 expr = expr.Resolve (ec);
2528 type = target_type.ResolveAsType (ec);
2532 if (type.IsStatic) {
2533 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2537 if (type.IsPointer) {
2538 if (ec.CurrentIterator != null) {
2539 UnsafeInsideIteratorError (ec, loc);
2540 } else if (!ec.IsUnsafe) {
2541 UnsafeError (ec, loc);
2545 eclass = ExprClass.Value;
2547 Constant c = expr as Constant;
2549 c = c.Reduce (ec, type);
2554 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2556 return EmptyCast.Create (res, type);
2561 protected override void CloneTo (CloneContext clonectx, Expression t)
2563 Cast target = (Cast) t;
2565 target.target_type = target_type.Clone (clonectx);
2566 target.expr = expr.Clone (clonectx);
2569 public override object Accept (StructuralVisitor visitor)
2571 return visitor.Visit (this);
2575 public class ImplicitCast : ShimExpression
2579 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2582 this.loc = expr.Location;
2584 this.arrayAccess = arrayAccess;
2587 protected override Expression DoResolve (ResolveContext ec)
2589 expr = expr.Resolve (ec);
2594 expr = ConvertExpressionToArrayIndex (ec, expr);
2596 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2602 public class DeclarationExpression : Expression, IMemoryLocation
2604 LocalVariableReference lvr;
2606 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2608 VariableType = variableType;
2609 Variable = variable;
2610 this.loc = variable.Location;
2613 public LocalVariable Variable { get; set; }
2614 public Expression Initializer { get; set; }
2615 public FullNamedExpression VariableType { get; set; }
2617 public void AddressOf (EmitContext ec, AddressOp mode)
2619 if (!Variable.Created)
2620 Variable.CreateBuilder (ec);
2622 if (Initializer != null) {
2623 lvr.EmitAssign (ec, Initializer, false, false);
2626 lvr.AddressOf (ec, mode);
2629 protected override void CloneTo (CloneContext clonectx, Expression t)
2631 var target = (DeclarationExpression) t;
2633 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2635 if (Initializer != null)
2636 target.Initializer = Initializer.Clone (clonectx);
2639 public override Expression CreateExpressionTree (ResolveContext rc)
2641 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2645 bool DoResolveCommon (ResolveContext rc)
2647 CheckExpressionVariable (rc);
2649 var var_expr = VariableType as VarExpr;
2650 if (var_expr != null) {
2651 type = InternalType.VarOutType;
2653 type = VariableType.ResolveAsType (rc);
2658 if (Initializer != null) {
2659 Initializer = Initializer.Resolve (rc);
2661 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2662 type = var_expr.Type;
2666 Variable.Type = type;
2667 lvr = new LocalVariableReference (Variable, loc);
2669 eclass = ExprClass.Variable;
2673 protected override Expression DoResolve (ResolveContext rc)
2675 if (DoResolveCommon (rc))
2681 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2683 if (lvr == null && DoResolveCommon (rc))
2684 lvr.ResolveLValue (rc, right_side);
2689 public override void Emit (EmitContext ec)
2691 throw new NotImplementedException ();
2694 public override void EmitPrepare (EmitContext ec)
2696 Variable.CreateBuilder (ec);
2701 // C# 2.0 Default value expression
2703 public class DefaultValueExpression : Expression
2707 public DefaultValueExpression (Expression expr, Location loc)
2713 public Expression Expr {
2719 public override bool IsSideEffectFree {
2725 public override bool ContainsEmitWithAwait ()
2730 public override Expression CreateExpressionTree (ResolveContext ec)
2732 Arguments args = new Arguments (2);
2733 args.Add (new Argument (this));
2734 args.Add (new Argument (new TypeOf (type, loc)));
2735 return CreateExpressionFactoryCall (ec, "Constant", args);
2738 protected override Expression DoResolve (ResolveContext ec)
2740 type = expr.ResolveAsType (ec);
2744 if (type.IsStatic) {
2745 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2749 return new NullLiteral (Location).ConvertImplicitly (type);
2751 if (TypeSpec.IsReferenceType (type))
2752 return new NullConstant (type, loc);
2754 Constant c = New.Constantify (type, expr.Location);
2758 eclass = ExprClass.Variable;
2762 public override void Emit (EmitContext ec)
2764 LocalTemporary temp_storage = new LocalTemporary(type);
2766 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2767 ec.Emit(OpCodes.Initobj, type);
2768 temp_storage.Emit(ec);
2769 temp_storage.Release (ec);
2773 public override SLE.Expression MakeExpression (BuilderContext ctx)
2775 return SLE.Expression.Default (type.GetMetaInfo ());
2779 protected override void CloneTo (CloneContext clonectx, Expression t)
2781 DefaultValueExpression target = (DefaultValueExpression) t;
2783 target.expr = expr.Clone (clonectx);
2786 public override object Accept (StructuralVisitor visitor)
2788 return visitor.Visit (this);
2793 /// Binary operators
2795 public class Binary : Expression, IDynamicBinder
2797 public class PredefinedOperator
2799 protected readonly TypeSpec left;
2800 protected readonly TypeSpec right;
2801 protected readonly TypeSpec left_unwrap;
2802 protected readonly TypeSpec right_unwrap;
2803 public readonly Operator OperatorsMask;
2804 public TypeSpec ReturnType;
2806 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2807 : this (ltype, rtype, op_mask, ltype)
2811 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2812 : this (type, type, op_mask, return_type)
2816 public PredefinedOperator (TypeSpec type, Operator op_mask)
2817 : this (type, type, op_mask, type)
2821 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2823 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2824 throw new InternalErrorException ("Only masked values can be used");
2826 if ((op_mask & Operator.NullableMask) != 0) {
2827 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2828 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2830 left_unwrap = ltype;
2831 right_unwrap = rtype;
2836 this.OperatorsMask = op_mask;
2837 this.ReturnType = return_type;
2840 public bool IsLifted {
2842 return (OperatorsMask & Operator.NullableMask) != 0;
2846 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2850 var left_expr = b.left;
2851 var right_expr = b.right;
2853 b.type = ReturnType;
2856 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2857 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2858 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2861 if (right_expr.IsNull) {
2862 if ((b.oper & Operator.EqualityMask) != 0) {
2863 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2864 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2865 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2866 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2867 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2869 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2870 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2872 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2873 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2875 return b.CreateLiftedValueTypeResult (rc, left);
2877 } else if (left_expr.IsNull) {
2878 if ((b.oper & Operator.EqualityMask) != 0) {
2879 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2880 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2881 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2882 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2883 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2885 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2886 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2888 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2889 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2891 return b.CreateLiftedValueTypeResult (rc, right);
2897 // A user operators does not support multiple user conversions, but decimal type
2898 // is considered to be predefined type therefore we apply predefined operators rules
2899 // and then look for decimal user-operator implementation
2901 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2902 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2903 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2905 return b.ResolveUserOperator (rc, b.left, b.right);
2908 c = right_expr as Constant;
2910 if (c.IsDefaultValue) {
2914 // (expr + 0) to expr
2915 // (expr - 0) to expr
2916 // (bool? | false) to bool?
2918 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2919 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2920 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2921 return ReducedExpression.Create (b.left, b).Resolve (rc);
2925 // Optimizes (value &/&& 0) to 0
2927 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2928 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2929 return ReducedExpression.Create (side_effect, b);
2933 // Optimizes (bool? & true) to bool?
2935 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2936 return ReducedExpression.Create (b.left, b).Resolve (rc);
2940 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2941 return ReducedExpression.Create (b.left, b).Resolve (rc);
2943 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2944 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2948 c = b.left as Constant;
2950 if (c.IsDefaultValue) {
2954 // (0 + expr) to expr
2955 // (false | bool?) to bool?
2957 if (b.oper == Operator.Addition ||
2958 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2959 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2960 return ReducedExpression.Create (b.right, b).Resolve (rc);
2964 // Optimizes (false && expr) to false
2966 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2967 // No rhs side-effects
2968 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2969 return ReducedExpression.Create (c, b);
2973 // Optimizes (0 & value) to 0
2975 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2976 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2977 return ReducedExpression.Create (side_effect, b);
2981 // Optimizes (true & bool?) to bool?
2983 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2984 return ReducedExpression.Create (b.right, b).Resolve (rc);
2988 // Optimizes (true || expr) to true
2990 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2991 // No rhs side-effects
2992 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2993 return ReducedExpression.Create (c, b);
2997 if (b.oper == Operator.Multiply && c.IsOneInteger)
2998 return ReducedExpression.Create (b.right, b).Resolve (rc);
3002 var lifted = new Nullable.LiftedBinaryOperator (b);
3004 TypeSpec ltype, rtype;
3005 if (b.left.Type.IsNullableType) {
3006 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
3007 ltype = left_unwrap;
3012 if (b.right.Type.IsNullableType) {
3013 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
3014 rtype = right_unwrap;
3019 lifted.Left = b.left.IsNull ?
3020 Nullable.LiftedNull.Create (ltype, b.left.Location) :
3021 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
3023 lifted.Right = b.right.IsNull ?
3024 Nullable.LiftedNull.Create (rtype, b.right.Location) :
3025 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
3027 return lifted.Resolve (rc);
3030 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3031 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3036 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3039 // We are dealing with primitive types only
3041 return left == ltype && ltype == rtype;
3044 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3047 if (left == lexpr.Type && right == rexpr.Type)
3050 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3051 Convert.ImplicitConversionExists (ec, rexpr, right);
3054 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3056 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3057 return best_operator;
3059 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3063 if (left != null && best_operator.left != null) {
3064 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3068 // When second argument is same as the first one, the result is same
3070 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3071 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3074 if (result == 0 || result > 2)
3077 return result == 1 ? best_operator : this;
3081 sealed class PredefinedStringOperator : PredefinedOperator
3083 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3084 : base (type, type, op_mask, retType)
3088 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3089 : base (ltype, rtype, op_mask, retType)
3093 public override Expression ConvertResult (ResolveContext ec, Binary b)
3096 // Use original expression for nullable arguments
3098 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3100 b.left = unwrap.Original;
3102 unwrap = b.right as Nullable.Unwrap;
3104 b.right = unwrap.Original;
3106 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3107 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3110 // Start a new concat expression using converted expression
3112 return StringConcat.Create (ec, b.left, b.right, b.loc);
3116 sealed class PredefinedEqualityOperator : PredefinedOperator
3118 MethodSpec equal_method, inequal_method;
3120 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3121 : base (arg, arg, Operator.EqualityMask, retType)
3125 public override Expression ConvertResult (ResolveContext ec, Binary b)
3127 b.type = ReturnType;
3129 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3130 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3132 Arguments args = new Arguments (2);
3133 args.Add (new Argument (b.left));
3134 args.Add (new Argument (b.right));
3137 if (b.oper == Operator.Equality) {
3138 if (equal_method == null) {
3139 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3140 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3141 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3142 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3144 throw new NotImplementedException (left.GetSignatureForError ());
3147 method = equal_method;
3149 if (inequal_method == null) {
3150 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3151 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3152 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3153 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3155 throw new NotImplementedException (left.GetSignatureForError ());
3158 method = inequal_method;
3161 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3165 class PredefinedPointerOperator : PredefinedOperator
3167 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3168 : base (ltype, rtype, op_mask)
3172 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3173 : base (ltype, rtype, op_mask, retType)
3177 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3178 : base (type, op_mask, return_type)
3182 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3185 if (!lexpr.Type.IsPointer)
3188 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3192 if (right == null) {
3193 if (!rexpr.Type.IsPointer)
3196 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3203 public override Expression ConvertResult (ResolveContext ec, Binary b)
3206 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3207 } else if (right != null) {
3208 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3211 TypeSpec r_type = ReturnType;
3212 Expression left_arg, right_arg;
3213 if (r_type == null) {
3216 right_arg = b.right;
3217 r_type = b.left.Type;
3221 r_type = b.right.Type;
3225 right_arg = b.right;
3228 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3233 public enum Operator {
3234 Multiply = 0 | ArithmeticMask,
3235 Division = 1 | ArithmeticMask,
3236 Modulus = 2 | ArithmeticMask,
3237 Addition = 3 | ArithmeticMask | AdditionMask,
3238 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3240 LeftShift = 5 | ShiftMask,
3241 RightShift = 6 | ShiftMask,
3243 LessThan = 7 | ComparisonMask | RelationalMask,
3244 GreaterThan = 8 | ComparisonMask | RelationalMask,
3245 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3246 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3247 Equality = 11 | ComparisonMask | EqualityMask,
3248 Inequality = 12 | ComparisonMask | EqualityMask,
3250 BitwiseAnd = 13 | BitwiseMask,
3251 ExclusiveOr = 14 | BitwiseMask,
3252 BitwiseOr = 15 | BitwiseMask,
3254 LogicalAnd = 16 | LogicalMask,
3255 LogicalOr = 17 | LogicalMask,
3260 ValuesOnlyMask = ArithmeticMask - 1,
3261 ArithmeticMask = 1 << 5,
3263 ComparisonMask = 1 << 7,
3264 EqualityMask = 1 << 8,
3265 BitwiseMask = 1 << 9,
3266 LogicalMask = 1 << 10,
3267 AdditionMask = 1 << 11,
3268 SubtractionMask = 1 << 12,
3269 RelationalMask = 1 << 13,
3271 DecomposedMask = 1 << 19,
3272 NullableMask = 1 << 20
3276 public enum State : byte
3280 UserOperatorsExcluded = 1 << 2
3283 readonly Operator oper;
3284 Expression left, right;
3286 ConvCast.Mode enum_conversion;
3288 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3289 : this (oper, left, right, State.Compound)
3293 public Binary (Operator oper, Expression left, Expression right, State state)
3294 : this (oper, left, right)
3299 public Binary (Operator oper, Expression left, Expression right)
3300 : this (oper, left, right, left.Location)
3304 public Binary (Operator oper, Expression left, Expression right, Location loc)
3314 public bool IsCompound {
3316 return (state & State.Compound) != 0;
3320 public Operator Oper {
3326 public Expression Left {
3332 public Expression Right {
3338 public override Location StartLocation {
3340 return left.StartLocation;
3347 /// Returns a stringified representation of the Operator
3349 string OperName (Operator oper)
3353 case Operator.Multiply:
3356 case Operator.Division:
3359 case Operator.Modulus:
3362 case Operator.Addition:
3365 case Operator.Subtraction:
3368 case Operator.LeftShift:
3371 case Operator.RightShift:
3374 case Operator.LessThan:
3377 case Operator.GreaterThan:
3380 case Operator.LessThanOrEqual:
3383 case Operator.GreaterThanOrEqual:
3386 case Operator.Equality:
3389 case Operator.Inequality:
3392 case Operator.BitwiseAnd:
3395 case Operator.BitwiseOr:
3398 case Operator.ExclusiveOr:
3401 case Operator.LogicalOr:
3404 case Operator.LogicalAnd:
3408 s = oper.ToString ();
3418 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3420 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3423 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3425 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3429 l = left.Type.GetSignatureForError ();
3430 r = right.Type.GetSignatureForError ();
3432 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3436 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3438 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3441 public override void FlowAnalysis (FlowAnalysisContext fc)
3444 // Optimized version when on-true/on-false data are not needed
3446 if ((oper & Operator.LogicalMask) == 0) {
3447 left.FlowAnalysis (fc);
3448 right.FlowAnalysis (fc);
3452 left.FlowAnalysisConditional (fc);
3453 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3454 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3456 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3457 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3458 right.FlowAnalysisConditional (fc);
3460 if (oper == Operator.LogicalOr)
3461 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3463 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3466 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3468 if ((oper & Operator.LogicalMask) == 0) {
3469 base.FlowAnalysisConditional (fc);
3473 left.FlowAnalysisConditional (fc);
3474 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3475 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3477 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3478 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3479 right.FlowAnalysisConditional (fc);
3481 var lc = left as Constant;
3482 if (oper == Operator.LogicalOr) {
3483 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3484 if (lc != null && lc.IsDefaultValue)
3485 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3487 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3489 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3490 if (lc != null && !lc.IsDefaultValue)
3491 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3493 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3498 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3500 string GetOperatorExpressionTypeName ()
3503 case Operator.Addition:
3504 return IsCompound ? "AddAssign" : "Add";
3505 case Operator.BitwiseAnd:
3506 return IsCompound ? "AndAssign" : "And";
3507 case Operator.BitwiseOr:
3508 return IsCompound ? "OrAssign" : "Or";
3509 case Operator.Division:
3510 return IsCompound ? "DivideAssign" : "Divide";
3511 case Operator.ExclusiveOr:
3512 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3513 case Operator.Equality:
3515 case Operator.GreaterThan:
3516 return "GreaterThan";
3517 case Operator.GreaterThanOrEqual:
3518 return "GreaterThanOrEqual";
3519 case Operator.Inequality:
3521 case Operator.LeftShift:
3522 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3523 case Operator.LessThan:
3525 case Operator.LessThanOrEqual:
3526 return "LessThanOrEqual";
3527 case Operator.LogicalAnd:
3529 case Operator.LogicalOr:
3531 case Operator.Modulus:
3532 return IsCompound ? "ModuloAssign" : "Modulo";
3533 case Operator.Multiply:
3534 return IsCompound ? "MultiplyAssign" : "Multiply";
3535 case Operator.RightShift:
3536 return IsCompound ? "RightShiftAssign" : "RightShift";
3537 case Operator.Subtraction:
3538 return IsCompound ? "SubtractAssign" : "Subtract";
3540 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3544 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3547 case Operator.Addition:
3548 return CSharp.Operator.OpType.Addition;
3549 case Operator.BitwiseAnd:
3550 case Operator.LogicalAnd:
3551 return CSharp.Operator.OpType.BitwiseAnd;
3552 case Operator.BitwiseOr:
3553 case Operator.LogicalOr:
3554 return CSharp.Operator.OpType.BitwiseOr;
3555 case Operator.Division:
3556 return CSharp.Operator.OpType.Division;
3557 case Operator.Equality:
3558 return CSharp.Operator.OpType.Equality;
3559 case Operator.ExclusiveOr:
3560 return CSharp.Operator.OpType.ExclusiveOr;
3561 case Operator.GreaterThan:
3562 return CSharp.Operator.OpType.GreaterThan;
3563 case Operator.GreaterThanOrEqual:
3564 return CSharp.Operator.OpType.GreaterThanOrEqual;
3565 case Operator.Inequality:
3566 return CSharp.Operator.OpType.Inequality;
3567 case Operator.LeftShift:
3568 return CSharp.Operator.OpType.LeftShift;
3569 case Operator.LessThan:
3570 return CSharp.Operator.OpType.LessThan;
3571 case Operator.LessThanOrEqual:
3572 return CSharp.Operator.OpType.LessThanOrEqual;
3573 case Operator.Modulus:
3574 return CSharp.Operator.OpType.Modulus;
3575 case Operator.Multiply:
3576 return CSharp.Operator.OpType.Multiply;
3577 case Operator.RightShift:
3578 return CSharp.Operator.OpType.RightShift;
3579 case Operator.Subtraction:
3580 return CSharp.Operator.OpType.Subtraction;
3582 throw new InternalErrorException (op.ToString ());
3586 public override bool ContainsEmitWithAwait ()
3588 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3591 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3596 case Operator.Multiply:
3597 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3598 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3599 opcode = OpCodes.Mul_Ovf;
3600 else if (!IsFloat (l))
3601 opcode = OpCodes.Mul_Ovf_Un;
3603 opcode = OpCodes.Mul;
3605 opcode = OpCodes.Mul;
3609 case Operator.Division:
3611 opcode = OpCodes.Div_Un;
3613 opcode = OpCodes.Div;
3616 case Operator.Modulus:
3618 opcode = OpCodes.Rem_Un;
3620 opcode = OpCodes.Rem;
3623 case Operator.Addition:
3624 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3625 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3626 opcode = OpCodes.Add_Ovf;
3627 else if (!IsFloat (l))
3628 opcode = OpCodes.Add_Ovf_Un;
3630 opcode = OpCodes.Add;
3632 opcode = OpCodes.Add;
3635 case Operator.Subtraction:
3636 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3637 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3638 opcode = OpCodes.Sub_Ovf;
3639 else if (!IsFloat (l))
3640 opcode = OpCodes.Sub_Ovf_Un;
3642 opcode = OpCodes.Sub;
3644 opcode = OpCodes.Sub;
3647 case Operator.RightShift:
3648 if (!(right is IntConstant)) {
3649 ec.EmitInt (GetShiftMask (l));
3650 ec.Emit (OpCodes.And);
3654 opcode = OpCodes.Shr_Un;
3656 opcode = OpCodes.Shr;
3659 case Operator.LeftShift:
3660 if (!(right is IntConstant)) {
3661 ec.EmitInt (GetShiftMask (l));
3662 ec.Emit (OpCodes.And);
3665 opcode = OpCodes.Shl;
3668 case Operator.Equality:
3669 opcode = OpCodes.Ceq;
3672 case Operator.Inequality:
3673 ec.Emit (OpCodes.Ceq);
3676 opcode = OpCodes.Ceq;
3679 case Operator.LessThan:
3681 opcode = OpCodes.Clt_Un;
3683 opcode = OpCodes.Clt;
3686 case Operator.GreaterThan:
3688 opcode = OpCodes.Cgt_Un;
3690 opcode = OpCodes.Cgt;
3693 case Operator.LessThanOrEqual:
3694 if (IsUnsigned (l) || IsFloat (l))
3695 ec.Emit (OpCodes.Cgt_Un);
3697 ec.Emit (OpCodes.Cgt);
3700 opcode = OpCodes.Ceq;
3703 case Operator.GreaterThanOrEqual:
3704 if (IsUnsigned (l) || IsFloat (l))
3705 ec.Emit (OpCodes.Clt_Un);
3707 ec.Emit (OpCodes.Clt);
3711 opcode = OpCodes.Ceq;
3714 case Operator.BitwiseOr:
3715 opcode = OpCodes.Or;
3718 case Operator.BitwiseAnd:
3719 opcode = OpCodes.And;
3722 case Operator.ExclusiveOr:
3723 opcode = OpCodes.Xor;
3727 throw new InternalErrorException (oper.ToString ());
3733 static int GetShiftMask (TypeSpec type)
3735 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3738 static bool IsUnsigned (TypeSpec t)
3740 switch (t.BuiltinType) {
3741 case BuiltinTypeSpec.Type.Char:
3742 case BuiltinTypeSpec.Type.UInt:
3743 case BuiltinTypeSpec.Type.ULong:
3744 case BuiltinTypeSpec.Type.UShort:
3745 case BuiltinTypeSpec.Type.Byte:
3752 static bool IsFloat (TypeSpec t)
3754 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3757 public Expression ResolveOperator (ResolveContext rc)
3759 eclass = ExprClass.Value;
3761 TypeSpec l = left.Type;
3762 TypeSpec r = right.Type;
3764 bool primitives_only = false;
3767 // Handles predefined primitive types
3769 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3770 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3771 if ((oper & Operator.ShiftMask) == 0) {
3772 if (!DoBinaryOperatorPromotion (rc))
3775 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3779 if (l.IsPointer || r.IsPointer)
3780 return ResolveOperatorPointer (rc, l, r);
3783 if ((state & State.UserOperatorsExcluded) == 0) {
3784 expr = ResolveUserOperator (rc, left, right);
3789 bool lenum = l.IsEnum;
3790 bool renum = r.IsEnum;
3791 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3795 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3796 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3801 if ((oper & Operator.BitwiseMask) != 0) {
3802 expr = EmptyCast.Create (expr, type);
3803 enum_conversion = GetEnumResultCast (type);
3805 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3806 expr = OptimizeAndOperation (expr);
3810 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3811 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3814 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3815 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3819 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3822 // We cannot break here there is also Enum + String possible match
3823 // which is not ambiguous with predefined enum operators
3826 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3827 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3831 } else if (l.IsDelegate || r.IsDelegate) {
3835 expr = ResolveOperatorDelegate (rc, l, r);
3837 // TODO: Can this be ambiguous
3845 // Equality operators are more complicated
3847 if ((oper & Operator.EqualityMask) != 0) {
3848 return ResolveEquality (rc, l, r, primitives_only);
3851 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3855 if (primitives_only)
3859 // Lifted operators have lower priority
3861 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3864 static bool IsEnumOrNullableEnum (TypeSpec type)
3866 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3870 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3871 // if 'left' is not an enumeration constant, create one from the type of 'right'
3872 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3875 case Operator.BitwiseOr:
3876 case Operator.BitwiseAnd:
3877 case Operator.ExclusiveOr:
3878 case Operator.Equality:
3879 case Operator.Inequality:
3880 case Operator.LessThan:
3881 case Operator.LessThanOrEqual:
3882 case Operator.GreaterThan:
3883 case Operator.GreaterThanOrEqual:
3884 if (left.Type.IsEnum)
3887 if (left.IsZeroInteger)
3888 return left.Reduce (ec, right.Type);
3892 case Operator.Addition:
3893 case Operator.Subtraction:
3896 case Operator.Multiply:
3897 case Operator.Division:
3898 case Operator.Modulus:
3899 case Operator.LeftShift:
3900 case Operator.RightShift:
3901 if (right.Type.IsEnum || left.Type.IsEnum)
3910 // The `|' operator used on types which were extended is dangerous
3912 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3914 OpcodeCast lcast = left as OpcodeCast;
3915 if (lcast != null) {
3916 if (IsUnsigned (lcast.UnderlyingType))
3920 OpcodeCast rcast = right as OpcodeCast;
3921 if (rcast != null) {
3922 if (IsUnsigned (rcast.UnderlyingType))
3926 if (lcast == null && rcast == null)
3929 // FIXME: consider constants
3931 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3932 ec.Report.Warning (675, 3, loc,
3933 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3934 ltype.GetSignatureForError ());
3937 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3939 return new PredefinedOperator[] {
3941 // Pointer arithmetic:
3943 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3944 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3945 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3946 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3948 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3949 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3950 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3951 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3954 // T* operator + (int y, T* x);
3955 // T* operator + (uint y, T *x);
3956 // T* operator + (long y, T *x);
3957 // T* operator + (ulong y, T *x);
3959 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3960 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3961 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3962 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3965 // long operator - (T* x, T *y)
3967 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3971 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3973 TypeSpec bool_type = types.Bool;
3976 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3977 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3978 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3979 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3980 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3981 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3982 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3984 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3985 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3986 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3987 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3988 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3989 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3990 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3992 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3993 // Remaining string operators are in lifted tables
3995 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3997 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3998 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3999 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
4003 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
4005 var types = module.Compiler.BuiltinTypes;
4008 // Not strictly lifted but need to be in second group otherwise expressions like
4009 // int + null would resolve to +(object, string) instead of +(int?, int?)
4011 var string_operators = new [] {
4012 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
4013 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
4016 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4017 if (nullable == null)
4018 return string_operators;
4020 var bool_type = types.Bool;
4022 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
4023 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4024 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4025 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4026 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4027 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4028 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4029 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4032 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4033 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4034 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4035 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4036 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4037 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4038 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4040 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4041 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4042 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4043 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4044 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4045 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4046 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4048 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4050 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4051 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4052 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4054 string_operators [0],
4055 string_operators [1]
4059 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4061 TypeSpec bool_type = types.Bool;
4064 new PredefinedEqualityOperator (types.String, bool_type),
4065 new PredefinedEqualityOperator (types.Delegate, bool_type),
4066 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4067 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4068 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4069 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4070 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4071 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4072 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4073 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4077 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4079 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4081 if (nullable == null)
4082 return new PredefinedOperator [0];
4084 var types = module.Compiler.BuiltinTypes;
4085 var bool_type = types.Bool;
4086 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4087 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4088 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4089 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4090 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4091 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4092 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4093 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4096 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4097 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4098 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4099 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4100 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4101 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4102 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4103 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4108 // 7.2.6.2 Binary numeric promotions
4110 bool DoBinaryOperatorPromotion (ResolveContext rc)
4112 TypeSpec ltype = left.Type;
4113 if (ltype.IsNullableType) {
4114 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4118 // This is numeric promotion code only
4120 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4123 TypeSpec rtype = right.Type;
4124 if (rtype.IsNullableType) {
4125 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4128 var lb = ltype.BuiltinType;
4129 var rb = rtype.BuiltinType;
4133 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4134 type = rc.BuiltinTypes.Decimal;
4135 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4136 type = rc.BuiltinTypes.Double;
4137 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4138 type = rc.BuiltinTypes.Float;
4139 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4140 type = rc.BuiltinTypes.ULong;
4142 if (IsSignedType (lb)) {
4143 expr = ConvertSignedConstant (left, type);
4147 } else if (IsSignedType (rb)) {
4148 expr = ConvertSignedConstant (right, type);
4154 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4155 type = rc.BuiltinTypes.Long;
4156 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4157 type = rc.BuiltinTypes.UInt;
4159 if (IsSignedType (lb)) {
4160 expr = ConvertSignedConstant (left, type);
4162 type = rc.BuiltinTypes.Long;
4163 } else if (IsSignedType (rb)) {
4164 expr = ConvertSignedConstant (right, type);
4166 type = rc.BuiltinTypes.Long;
4169 type = rc.BuiltinTypes.Int;
4172 if (ltype != type) {
4173 expr = PromoteExpression (rc, left, type);
4180 if (rtype != type) {
4181 expr = PromoteExpression (rc, right, type);
4191 static bool IsSignedType (BuiltinTypeSpec.Type type)
4194 case BuiltinTypeSpec.Type.Int:
4195 case BuiltinTypeSpec.Type.Short:
4196 case BuiltinTypeSpec.Type.SByte:
4197 case BuiltinTypeSpec.Type.Long:
4204 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4206 var c = expr as Constant;
4210 return c.ConvertImplicitly (type);
4213 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4215 if (expr.Type.IsNullableType) {
4216 return Convert.ImplicitConversionStandard (rc, expr,
4217 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4220 var c = expr as Constant;
4222 return c.ConvertImplicitly (type);
4224 return Convert.ImplicitNumericConversion (expr, type);
4227 protected override Expression DoResolve (ResolveContext ec)
4232 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4233 left = ((ParenthesizedExpression) left).Expr;
4234 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4238 if (left.eclass == ExprClass.Type) {
4239 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4243 left = left.Resolve (ec);
4248 right = right.Resolve (ec);
4252 Constant lc = left as Constant;
4253 Constant rc = right as Constant;
4255 // The conversion rules are ignored in enum context but why
4256 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4257 lc = EnumLiftUp (ec, lc, rc);
4259 rc = EnumLiftUp (ec, rc, lc);
4262 if (rc != null && lc != null) {
4263 int prev_e = ec.Report.Errors;
4264 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4265 if (e != null || ec.Report.Errors != prev_e)
4269 // Comparison warnings
4270 if ((oper & Operator.ComparisonMask) != 0) {
4271 if (left.Equals (right)) {
4272 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4274 CheckOutOfRangeComparison (ec, lc, right.Type);
4275 CheckOutOfRangeComparison (ec, rc, left.Type);
4278 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4279 return DoResolveDynamic (ec);
4281 return DoResolveCore (ec, left, right);
4284 Expression DoResolveDynamic (ResolveContext rc)
4287 var rt = right.Type;
4288 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4289 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4290 Error_OperatorCannotBeApplied (rc, left, right);
4297 // Special handling for logical boolean operators which require rhs not to be
4298 // evaluated based on lhs value
4300 if ((oper & Operator.LogicalMask) != 0) {
4301 Expression cond_left, cond_right, expr;
4303 args = new Arguments (2);
4305 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4306 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4308 var cond_args = new Arguments (1);
4309 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4312 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4313 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4315 left = temp.CreateReferenceExpression (rc, loc);
4316 if (oper == Operator.LogicalAnd) {
4317 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4320 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4324 args.Add (new Argument (left));
4325 args.Add (new Argument (right));
4326 cond_right = new DynamicExpressionStatement (this, args, loc);
4328 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4330 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4331 rc.Report.Error (7083, left.Location,
4332 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4333 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4337 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4338 args.Add (new Argument (right));
4339 right = new DynamicExpressionStatement (this, args, loc);
4342 // bool && dynamic => (temp = left) ? temp && right : temp;
4343 // bool || dynamic => (temp = left) ? temp : temp || right;
4345 if (oper == Operator.LogicalAnd) {
4347 cond_right = temp.CreateReferenceExpression (rc, loc);
4349 cond_left = temp.CreateReferenceExpression (rc, loc);
4353 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4356 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4359 args = new Arguments (2);
4360 args.Add (new Argument (left));
4361 args.Add (new Argument (right));
4362 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4365 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4367 Expression expr = ResolveOperator (ec);
4369 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4371 if (left == null || right == null)
4372 throw new InternalErrorException ("Invalid conversion");
4374 if (oper == Operator.BitwiseOr)
4375 CheckBitwiseOrOnSignExtended (ec);
4380 public override SLE.Expression MakeExpression (BuilderContext ctx)
4382 return MakeExpression (ctx, left, right);
4385 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4387 var le = left.MakeExpression (ctx);
4388 var re = right.MakeExpression (ctx);
4389 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4392 case Operator.Addition:
4393 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4394 case Operator.BitwiseAnd:
4395 return SLE.Expression.And (le, re);
4396 case Operator.BitwiseOr:
4397 return SLE.Expression.Or (le, re);
4398 case Operator.Division:
4399 return SLE.Expression.Divide (le, re);
4400 case Operator.Equality:
4401 return SLE.Expression.Equal (le, re);
4402 case Operator.ExclusiveOr:
4403 return SLE.Expression.ExclusiveOr (le, re);
4404 case Operator.GreaterThan:
4405 return SLE.Expression.GreaterThan (le, re);
4406 case Operator.GreaterThanOrEqual:
4407 return SLE.Expression.GreaterThanOrEqual (le, re);
4408 case Operator.Inequality:
4409 return SLE.Expression.NotEqual (le, re);
4410 case Operator.LeftShift:
4411 return SLE.Expression.LeftShift (le, re);
4412 case Operator.LessThan:
4413 return SLE.Expression.LessThan (le, re);
4414 case Operator.LessThanOrEqual:
4415 return SLE.Expression.LessThanOrEqual (le, re);
4416 case Operator.LogicalAnd:
4417 return SLE.Expression.AndAlso (le, re);
4418 case Operator.LogicalOr:
4419 return SLE.Expression.OrElse (le, re);
4420 case Operator.Modulus:
4421 return SLE.Expression.Modulo (le, re);
4422 case Operator.Multiply:
4423 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4424 case Operator.RightShift:
4425 return SLE.Expression.RightShift (le, re);
4426 case Operator.Subtraction:
4427 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4429 throw new NotImplementedException (oper.ToString ());
4434 // D operator + (D x, D y)
4435 // D operator - (D x, D y)
4437 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4439 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4441 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4442 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4447 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4448 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4458 MethodSpec method = null;
4459 Arguments args = new Arguments (2);
4460 args.Add (new Argument (left));
4461 args.Add (new Argument (right));
4463 if (oper == Operator.Addition) {
4464 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4465 } else if (oper == Operator.Subtraction) {
4466 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4470 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4472 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4473 return new ClassCast (expr, l);
4477 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4479 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4482 // bool operator == (E x, E y);
4483 // bool operator != (E x, E y);
4484 // bool operator < (E x, E y);
4485 // bool operator > (E x, E y);
4486 // bool operator <= (E x, E y);
4487 // bool operator >= (E x, E y);
4489 // E operator & (E x, E y);
4490 // E operator | (E x, E y);
4491 // E operator ^ (E x, E y);
4494 if ((oper & Operator.ComparisonMask) != 0) {
4495 type = rc.BuiltinTypes.Bool;
4501 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4507 if (ltype == rtype) {
4511 var lifted = new Nullable.LiftedBinaryOperator (this);
4513 lifted.Right = right;
4514 return lifted.Resolve (rc);
4517 if (renum && !ltype.IsNullableType) {
4518 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4523 } else if (lenum && !rtype.IsNullableType) {
4524 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4532 // Now try lifted version of predefined operator
4534 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4535 if (nullable_type != null) {
4536 if (renum && !ltype.IsNullableType) {
4537 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4539 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4542 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4545 if ((oper & Operator.BitwiseMask) != 0)
4549 if ((oper & Operator.BitwiseMask) != 0)
4550 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4552 return CreateLiftedValueTypeResult (rc, rtype);
4556 var lifted = new Nullable.LiftedBinaryOperator (this);
4558 lifted.Right = right;
4559 return lifted.Resolve (rc);
4561 } else if (lenum && !rtype.IsNullableType) {
4562 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4564 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4567 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4570 if ((oper & Operator.BitwiseMask) != 0)
4574 if ((oper & Operator.BitwiseMask) != 0)
4575 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4577 return CreateLiftedValueTypeResult (rc, ltype);
4581 var lifted = new Nullable.LiftedBinaryOperator (this);
4583 lifted.Right = expr;
4584 return lifted.Resolve (rc);
4586 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4587 Nullable.Unwrap unwrap = null;
4588 if (left.IsNull || right.IsNull) {
4589 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4590 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4592 if ((oper & Operator.RelationalMask) != 0)
4593 return CreateLiftedValueTypeResult (rc, rtype);
4595 if ((oper & Operator.BitwiseMask) != 0)
4596 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4599 return CreateLiftedValueTypeResult (rc, left.Type);
4601 // Equality operators are valid between E? and null
4603 unwrap = new Nullable.Unwrap (right);
4605 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4609 if ((oper & Operator.BitwiseMask) != 0)
4614 var lifted = new Nullable.LiftedBinaryOperator (this);
4616 lifted.Right = right;
4617 lifted.UnwrapRight = unwrap;
4618 return lifted.Resolve (rc);
4620 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4621 Nullable.Unwrap unwrap = null;
4622 if (right.IsNull || left.IsNull) {
4623 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4624 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4626 if ((oper & Operator.RelationalMask) != 0)
4627 return CreateLiftedValueTypeResult (rc, ltype);
4629 if ((oper & Operator.BitwiseMask) != 0)
4630 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4633 return CreateLiftedValueTypeResult (rc, right.Type);
4635 // Equality operators are valid between E? and null
4637 unwrap = new Nullable.Unwrap (left);
4639 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4643 if ((oper & Operator.BitwiseMask) != 0)
4648 var lifted = new Nullable.LiftedBinaryOperator (this);
4650 lifted.UnwrapLeft = unwrap;
4651 lifted.Right = expr;
4652 return lifted.Resolve (rc);
4660 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4662 TypeSpec underlying_type;
4663 if (expr.Type.IsNullableType) {
4664 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4666 underlying_type = EnumSpec.GetUnderlyingType (nt);
4668 underlying_type = nt;
4669 } else if (expr.Type.IsEnum) {
4670 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4672 underlying_type = expr.Type;
4675 switch (underlying_type.BuiltinType) {
4676 case BuiltinTypeSpec.Type.SByte:
4677 case BuiltinTypeSpec.Type.Byte:
4678 case BuiltinTypeSpec.Type.Short:
4679 case BuiltinTypeSpec.Type.UShort:
4680 underlying_type = rc.BuiltinTypes.Int;
4684 if (expr.Type.IsNullableType || liftType)
4685 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4687 if (expr.Type == underlying_type)
4690 return EmptyCast.Create (expr, underlying_type);
4693 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4696 // U operator - (E e, E f)
4697 // E operator - (E e, U x) // Internal decomposition operator
4698 // E operator - (U x, E e) // Internal decomposition operator
4700 // E operator + (E e, U x)
4701 // E operator + (U x, E e)
4710 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4716 if (!enum_type.IsNullableType) {
4717 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4719 if (oper == Operator.Subtraction)
4720 expr = ConvertEnumSubtractionResult (rc, expr);
4722 expr = ConvertEnumAdditionalResult (expr, enum_type);
4724 enum_conversion = GetEnumResultCast (expr.Type);
4729 var nullable = rc.Module.PredefinedTypes.Nullable;
4732 // Don't try nullable version when nullable type is undefined
4734 if (!nullable.IsDefined)
4737 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4740 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4742 if (oper == Operator.Subtraction)
4743 expr = ConvertEnumSubtractionResult (rc, expr);
4745 expr = ConvertEnumAdditionalResult (expr, enum_type);
4747 enum_conversion = GetEnumResultCast (expr.Type);
4753 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4755 return EmptyCast.Create (expr, enumType);
4758 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4761 // Enumeration subtraction has different result type based on
4764 TypeSpec result_type;
4765 if (left.Type == right.Type) {
4766 var c = right as EnumConstant;
4767 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4769 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4770 // E which is not what expressions E - 1 or 0 - E return
4772 result_type = left.Type;
4774 result_type = left.Type.IsNullableType ?
4775 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4776 EnumSpec.GetUnderlyingType (left.Type);
4779 if (IsEnumOrNullableEnum (left.Type)) {
4780 result_type = left.Type;
4782 result_type = right.Type;
4785 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4786 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4789 return EmptyCast.Create (expr, result_type);
4792 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4794 if (type.IsNullableType)
4795 type = Nullable.NullableInfo.GetUnderlyingType (type);
4798 type = EnumSpec.GetUnderlyingType (type);
4800 switch (type.BuiltinType) {
4801 case BuiltinTypeSpec.Type.SByte:
4802 return ConvCast.Mode.I4_I1;
4803 case BuiltinTypeSpec.Type.Byte:
4804 return ConvCast.Mode.I4_U1;
4805 case BuiltinTypeSpec.Type.Short:
4806 return ConvCast.Mode.I4_I2;
4807 case BuiltinTypeSpec.Type.UShort:
4808 return ConvCast.Mode.I4_U2;
4815 // Equality operators rules
4817 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4820 type = ec.BuiltinTypes.Bool;
4821 bool no_arg_conv = false;
4823 if (!primitives_only) {
4826 // a, Both operands are reference-type values or the value null
4827 // b, One operand is a value of type T where T is a type-parameter and
4828 // the other operand is the value null. Furthermore T does not have the
4829 // value type constraint
4831 // LAMESPEC: Very confusing details in the specification, basically any
4832 // reference like type-parameter is allowed
4834 var tparam_l = l as TypeParameterSpec;
4835 var tparam_r = r as TypeParameterSpec;
4836 if (tparam_l != null) {
4837 if (right is NullLiteral) {
4838 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4841 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4845 if (!tparam_l.IsReferenceType)
4848 l = tparam_l.GetEffectiveBase ();
4849 left = new BoxedCast (left, l);
4850 } else if (left is NullLiteral && tparam_r == null) {
4851 if (TypeSpec.IsReferenceType (r))
4854 if (r.Kind == MemberKind.InternalCompilerType)
4858 if (tparam_r != null) {
4859 if (left is NullLiteral) {
4860 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4863 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4867 if (!tparam_r.IsReferenceType)
4870 r = tparam_r.GetEffectiveBase ();
4871 right = new BoxedCast (right, r);
4872 } else if (right is NullLiteral) {
4873 if (TypeSpec.IsReferenceType (l))
4876 if (l.Kind == MemberKind.InternalCompilerType)
4881 // LAMESPEC: method groups can be compared when they convert to other side delegate
4884 if (right.eclass == ExprClass.MethodGroup) {
4885 result = Convert.ImplicitConversion (ec, right, l, loc);
4891 } else if (r.IsDelegate && l != r) {
4894 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4895 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4902 no_arg_conv = l == r && !l.IsStruct;
4907 // bool operator != (string a, string b)
4908 // bool operator == (string a, string b)
4910 // bool operator != (Delegate a, Delegate b)
4911 // bool operator == (Delegate a, Delegate b)
4913 // bool operator != (bool a, bool b)
4914 // bool operator == (bool a, bool b)
4916 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4917 // they implement an implicit conversion to any of types above. This does
4918 // not apply when both operands are of same reference type
4920 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4921 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4926 // Now try lifted version of predefined operators
4928 if (no_arg_conv && !l.IsNullableType) {
4930 // Optimizes cases which won't match
4933 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4939 // The == and != operators permit one operand to be a value of a nullable
4940 // type and the other to be the null literal, even if no predefined or user-defined
4941 // operator (in unlifted or lifted form) exists for the operation.
4943 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4944 var lifted = new Nullable.LiftedBinaryOperator (this);
4946 lifted.Right = right;
4947 return lifted.Resolve (ec);
4952 // bool operator != (object a, object b)
4953 // bool operator == (object a, object b)
4955 // An explicit reference conversion exists from the
4956 // type of either operand to the type of the other operand.
4959 // Optimize common path
4961 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4964 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4965 !Convert.ExplicitReferenceConversionExists (r, l))
4968 // Reject allowed explicit conversions like int->object
4969 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4972 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4973 ec.Report.Warning (253, 2, loc,
4974 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4975 l.GetSignatureForError ());
4977 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4978 ec.Report.Warning (252, 2, loc,
4979 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4980 r.GetSignatureForError ());
4986 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4989 // bool operator == (void* x, void* y);
4990 // bool operator != (void* x, void* y);
4991 // bool operator < (void* x, void* y);
4992 // bool operator > (void* x, void* y);
4993 // bool operator <= (void* x, void* y);
4994 // bool operator >= (void* x, void* y);
4996 if ((oper & Operator.ComparisonMask) != 0) {
4999 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
5006 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
5012 type = ec.BuiltinTypes.Bool;
5016 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
5020 // Build-in operators method overloading
5022 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
5024 PredefinedOperator best_operator = null;
5025 TypeSpec l = left.Type;
5026 TypeSpec r = right.Type;
5027 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5029 foreach (PredefinedOperator po in operators) {
5030 if ((po.OperatorsMask & oper_mask) == 0)
5033 if (primitives_only) {
5034 if (!po.IsPrimitiveApplicable (l, r))
5037 if (!po.IsApplicable (ec, left, right))
5041 if (best_operator == null) {
5043 if (primitives_only)
5049 best_operator = po.ResolveBetterOperator (ec, best_operator);
5051 if (best_operator == null) {
5052 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5053 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5060 if (best_operator == null)
5063 return best_operator.ConvertResult (ec, this);
5067 // Optimize & constant expressions with 0 value
5069 Expression OptimizeAndOperation (Expression expr)
5071 Constant rc = right as Constant;
5072 Constant lc = left as Constant;
5073 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5075 // The result is a constant with side-effect
5077 Constant side_effect = rc == null ?
5078 new SideEffectConstant (lc, right, loc) :
5079 new SideEffectConstant (rc, left, loc);
5081 return ReducedExpression.Create (side_effect, expr);
5088 // Value types can be compared with the null literal because of the lifting
5089 // language rules. However the result is always true or false.
5091 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5093 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5094 type = rc.BuiltinTypes.Bool;
5098 // FIXME: Handle side effect constants
5099 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5101 if ((Oper & Operator.EqualityMask) != 0) {
5102 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5103 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5105 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5106 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5113 // Performs user-operator overloading
5115 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5117 Expression oper_expr;
5119 var op = ConvertBinaryToUserOperator (oper);
5121 if (l.IsNullableType)
5122 l = Nullable.NullableInfo.GetUnderlyingType (l);
5124 if (r.IsNullableType)
5125 r = Nullable.NullableInfo.GetUnderlyingType (r);
5127 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5128 IList<MemberSpec> right_operators = null;
5131 right_operators = MemberCache.GetUserOperator (r, op, false);
5132 if (right_operators == null && left_operators == null)
5134 } else if (left_operators == null) {
5138 Arguments args = new Arguments (2);
5139 Argument larg = new Argument (left);
5141 Argument rarg = new Argument (right);
5145 // User-defined operator implementations always take precedence
5146 // over predefined operator implementations
5148 if (left_operators != null && right_operators != null) {
5149 left_operators = CombineUserOperators (left_operators, right_operators);
5150 } else if (right_operators != null) {
5151 left_operators = right_operators;
5154 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5155 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5157 var res = new OverloadResolver (left_operators, restr, loc);
5159 var oper_method = res.ResolveOperator (rc, ref args);
5160 if (oper_method == null) {
5162 // Logical && and || cannot be lifted
5164 if ((oper & Operator.LogicalMask) != 0)
5168 // Apply lifted user operators only for liftable types. Implicit conversion
5169 // to nullable types is not allowed
5171 if (!IsLiftedOperatorApplicable ())
5174 // TODO: Cache the result in module container
5175 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5176 if (lifted_methods == null)
5179 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5181 oper_method = res.ResolveOperator (rc, ref args);
5182 if (oper_method == null)
5185 MethodSpec best_original = null;
5186 foreach (MethodSpec ms in left_operators) {
5187 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5193 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5195 // Expression trees use lifted notation in this case
5197 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5198 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5201 var ptypes = best_original.Parameters.Types;
5203 if (left.IsNull || right.IsNull) {
5205 // The lifted operator produces a null value if one or both operands are null
5207 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5208 type = oper_method.ReturnType;
5209 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5213 // The lifted operator produces the value false if one or both operands are null for
5214 // relational operators.
5216 if ((oper & Operator.RelationalMask) != 0) {
5218 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5219 // because return type is actually bool
5221 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5224 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5225 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5229 type = oper_method.ReturnType;
5230 var lifted = new Nullable.LiftedBinaryOperator (this);
5231 lifted.UserOperator = best_original;
5233 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5234 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5237 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5238 lifted.UnwrapRight = new Nullable.Unwrap (right);
5241 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5242 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5244 return lifted.Resolve (rc);
5247 if ((oper & Operator.LogicalMask) != 0) {
5248 // TODO: CreateExpressionTree is allocated every time
5249 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5250 oper == Operator.LogicalAnd, loc).Resolve (rc);
5252 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5255 this.left = larg.Expr;
5256 this.right = rarg.Expr;
5261 bool IsLiftedOperatorApplicable ()
5263 if (left.Type.IsNullableType) {
5264 if ((oper & Operator.EqualityMask) != 0)
5265 return !right.IsNull;
5270 if (right.Type.IsNullableType) {
5271 if ((oper & Operator.EqualityMask) != 0)
5272 return !left.IsNull;
5277 if (TypeSpec.IsValueType (left.Type))
5278 return right.IsNull;
5280 if (TypeSpec.IsValueType (right.Type))
5286 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5288 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5289 if (nullable_type == null)
5293 // Lifted operators permit predefined and user-defined operators that operate
5294 // on non-nullable value types to also be used with nullable forms of those types.
5295 // Lifted operators are constructed from predefined and user-defined operators
5296 // that meet certain requirements
5298 List<MemberSpec> lifted = null;
5299 foreach (MethodSpec oper in operators) {
5301 if ((Oper & Operator.ComparisonMask) != 0) {
5303 // Result type must be of type bool for lifted comparison operators
5305 rt = oper.ReturnType;
5306 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5309 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5315 var ptypes = oper.Parameters.Types;
5316 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5320 // LAMESPEC: I am not sure why but for equality operators to be lifted
5321 // both types have to match
5323 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5327 lifted = new List<MemberSpec> ();
5330 // The lifted form is constructed by adding a single ? modifier to each operand and
5331 // result type except for comparison operators where return type is bool
5334 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5336 var parameters = ParametersCompiled.CreateFullyResolved (
5337 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5338 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5340 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5341 rt, parameters, oper.Modifiers);
5343 lifted.Add (lifted_op);
5350 // Merge two sets of user operators into one, they are mostly distinguish
5351 // except when they share base type and it contains an operator
5353 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5355 var combined = new List<MemberSpec> (left.Count + right.Count);
5356 combined.AddRange (left);
5357 foreach (var r in right) {
5359 foreach (var l in left) {
5360 if (l.DeclaringType == r.DeclaringType) {
5373 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5375 if (c is IntegralConstant || c is CharConstant) {
5377 c.ConvertExplicitly (true, type);
5378 } catch (OverflowException) {
5379 ec.Report.Warning (652, 2, loc,
5380 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5381 type.GetSignatureForError ());
5387 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5388 /// context of a conditional bool expression. This function will return
5389 /// false if it is was possible to use EmitBranchable, or true if it was.
5391 /// The expression's code is generated, and we will generate a branch to `target'
5392 /// if the resulting expression value is equal to isTrue
5394 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5396 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5397 left = left.EmitToField (ec);
5399 if ((oper & Operator.LogicalMask) == 0) {
5400 right = right.EmitToField (ec);
5405 // This is more complicated than it looks, but its just to avoid
5406 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5407 // but on top of that we want for == and != to use a special path
5408 // if we are comparing against null
5410 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5411 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5414 // put the constant on the rhs, for simplicity
5416 if (left is Constant) {
5417 Expression swap = right;
5423 // brtrue/brfalse works with native int only
5425 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5426 left.EmitBranchable (ec, target, my_on_true);
5429 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5430 // right is a boolean, and it's not 'false' => it is 'true'
5431 left.EmitBranchable (ec, target, !my_on_true);
5435 } else if (oper == Operator.LogicalAnd) {
5438 Label tests_end = ec.DefineLabel ();
5440 left.EmitBranchable (ec, tests_end, false);
5441 right.EmitBranchable (ec, target, true);
5442 ec.MarkLabel (tests_end);
5445 // This optimizes code like this
5446 // if (true && i > 4)
5448 if (!(left is Constant))
5449 left.EmitBranchable (ec, target, false);
5451 if (!(right is Constant))
5452 right.EmitBranchable (ec, target, false);
5457 } else if (oper == Operator.LogicalOr){
5459 left.EmitBranchable (ec, target, true);
5460 right.EmitBranchable (ec, target, true);
5463 Label tests_end = ec.DefineLabel ();
5464 left.EmitBranchable (ec, tests_end, true);
5465 right.EmitBranchable (ec, target, false);
5466 ec.MarkLabel (tests_end);
5471 } else if ((oper & Operator.ComparisonMask) == 0) {
5472 base.EmitBranchable (ec, target, on_true);
5479 TypeSpec t = left.Type;
5480 bool is_float = IsFloat (t);
5481 bool is_unsigned = is_float || IsUnsigned (t);
5484 case Operator.Equality:
5486 ec.Emit (OpCodes.Beq, target);
5488 ec.Emit (OpCodes.Bne_Un, target);
5491 case Operator.Inequality:
5493 ec.Emit (OpCodes.Bne_Un, target);
5495 ec.Emit (OpCodes.Beq, target);
5498 case Operator.LessThan:
5500 if (is_unsigned && !is_float)
5501 ec.Emit (OpCodes.Blt_Un, target);
5503 ec.Emit (OpCodes.Blt, target);
5506 ec.Emit (OpCodes.Bge_Un, target);
5508 ec.Emit (OpCodes.Bge, target);
5511 case Operator.GreaterThan:
5513 if (is_unsigned && !is_float)
5514 ec.Emit (OpCodes.Bgt_Un, target);
5516 ec.Emit (OpCodes.Bgt, target);
5519 ec.Emit (OpCodes.Ble_Un, target);
5521 ec.Emit (OpCodes.Ble, target);
5524 case Operator.LessThanOrEqual:
5526 if (is_unsigned && !is_float)
5527 ec.Emit (OpCodes.Ble_Un, target);
5529 ec.Emit (OpCodes.Ble, target);
5532 ec.Emit (OpCodes.Bgt_Un, target);
5534 ec.Emit (OpCodes.Bgt, target);
5538 case Operator.GreaterThanOrEqual:
5540 if (is_unsigned && !is_float)
5541 ec.Emit (OpCodes.Bge_Un, target);
5543 ec.Emit (OpCodes.Bge, target);
5546 ec.Emit (OpCodes.Blt_Un, target);
5548 ec.Emit (OpCodes.Blt, target);
5551 throw new InternalErrorException (oper.ToString ());
5555 public override void Emit (EmitContext ec)
5557 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5558 left = left.EmitToField (ec);
5560 if ((oper & Operator.LogicalMask) == 0) {
5561 right = right.EmitToField (ec);
5566 // Handle short-circuit operators differently
5569 if ((oper & Operator.LogicalMask) != 0) {
5570 Label load_result = ec.DefineLabel ();
5571 Label end = ec.DefineLabel ();
5573 bool is_or = oper == Operator.LogicalOr;
5574 left.EmitBranchable (ec, load_result, is_or);
5576 ec.Emit (OpCodes.Br_S, end);
5578 ec.MarkLabel (load_result);
5579 ec.EmitInt (is_or ? 1 : 0);
5585 // Optimize zero-based operations which cannot be optimized at expression level
5587 if (oper == Operator.Subtraction) {
5588 var lc = left as IntegralConstant;
5589 if (lc != null && lc.IsDefaultValue) {
5591 ec.Emit (OpCodes.Neg);
5596 EmitOperator (ec, left, right);
5599 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5604 EmitOperatorOpcode (ec, oper, left.Type, right);
5607 // Emit result enumerable conversion this way because it's quite complicated get it
5608 // to resolved tree because expression tree cannot see it.
5610 if (enum_conversion != 0)
5611 ConvCast.Emit (ec, enum_conversion);
5614 public override void EmitSideEffect (EmitContext ec)
5616 if ((oper & Operator.LogicalMask) != 0 ||
5617 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5618 base.EmitSideEffect (ec);
5620 left.EmitSideEffect (ec);
5621 right.EmitSideEffect (ec);
5625 public override Expression EmitToField (EmitContext ec)
5627 if ((oper & Operator.LogicalMask) == 0) {
5628 var await_expr = left as Await;
5629 if (await_expr != null && right.IsSideEffectFree) {
5630 await_expr.Statement.EmitPrologue (ec);
5631 left = await_expr.Statement.GetResultExpression (ec);
5635 await_expr = right as Await;
5636 if (await_expr != null && left.IsSideEffectFree) {
5637 await_expr.Statement.EmitPrologue (ec);
5638 right = await_expr.Statement.GetResultExpression (ec);
5643 return base.EmitToField (ec);
5646 protected override void CloneTo (CloneContext clonectx, Expression t)
5648 Binary target = (Binary) t;
5650 target.left = left.Clone (clonectx);
5651 target.right = right.Clone (clonectx);
5654 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5656 Arguments binder_args = new Arguments (4);
5658 MemberAccess sle = new MemberAccess (new MemberAccess (
5659 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5661 CSharpBinderFlags flags = 0;
5662 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5663 flags = CSharpBinderFlags.CheckedContext;
5665 if ((oper & Operator.LogicalMask) != 0)
5666 flags |= CSharpBinderFlags.BinaryOperationLogical;
5668 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5669 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5670 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5671 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5673 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5676 public override Expression CreateExpressionTree (ResolveContext ec)
5678 return CreateExpressionTree (ec, null);
5681 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5684 bool lift_arg = false;
5687 case Operator.Addition:
5688 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5689 method_name = "AddChecked";
5691 method_name = "Add";
5693 case Operator.BitwiseAnd:
5694 method_name = "And";
5696 case Operator.BitwiseOr:
5699 case Operator.Division:
5700 method_name = "Divide";
5702 case Operator.Equality:
5703 method_name = "Equal";
5706 case Operator.ExclusiveOr:
5707 method_name = "ExclusiveOr";
5709 case Operator.GreaterThan:
5710 method_name = "GreaterThan";
5713 case Operator.GreaterThanOrEqual:
5714 method_name = "GreaterThanOrEqual";
5717 case Operator.Inequality:
5718 method_name = "NotEqual";
5721 case Operator.LeftShift:
5722 method_name = "LeftShift";
5724 case Operator.LessThan:
5725 method_name = "LessThan";
5728 case Operator.LessThanOrEqual:
5729 method_name = "LessThanOrEqual";
5732 case Operator.LogicalAnd:
5733 method_name = "AndAlso";
5735 case Operator.LogicalOr:
5736 method_name = "OrElse";
5738 case Operator.Modulus:
5739 method_name = "Modulo";
5741 case Operator.Multiply:
5742 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5743 method_name = "MultiplyChecked";
5745 method_name = "Multiply";
5747 case Operator.RightShift:
5748 method_name = "RightShift";
5750 case Operator.Subtraction:
5751 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5752 method_name = "SubtractChecked";
5754 method_name = "Subtract";
5758 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5761 Arguments args = new Arguments (2);
5762 args.Add (new Argument (left.CreateExpressionTree (ec)));
5763 args.Add (new Argument (right.CreateExpressionTree (ec)));
5764 if (method != null) {
5766 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5768 args.Add (new Argument (method));
5771 return CreateExpressionFactoryCall (ec, method_name, args);
5774 public override object Accept (StructuralVisitor visitor)
5776 return visitor.Visit (this);
5782 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5783 // b, c, d... may be strings or objects.
5785 public class StringConcat : Expression
5787 Arguments arguments;
5789 StringConcat (Location loc)
5792 arguments = new Arguments (2);
5795 public override bool ContainsEmitWithAwait ()
5797 return arguments.ContainsEmitWithAwait ();
5800 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5802 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5803 throw new ArgumentException ();
5805 var s = new StringConcat (loc);
5806 s.type = rc.BuiltinTypes.String;
5807 s.eclass = ExprClass.Value;
5809 s.Append (rc, left);
5810 s.Append (rc, right);
5814 public override Expression CreateExpressionTree (ResolveContext ec)
5816 Argument arg = arguments [0];
5817 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5821 // Creates nested calls tree from an array of arguments used for IL emit
5823 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5825 Arguments concat_args = new Arguments (2);
5826 Arguments add_args = new Arguments (3);
5828 concat_args.Add (left);
5829 add_args.Add (new Argument (left_etree));
5831 concat_args.Add (arguments [pos]);
5832 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5834 var methods = GetConcatMethodCandidates ();
5835 if (methods == null)
5838 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5839 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5843 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5845 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5846 if (++pos == arguments.Count)
5849 left = new Argument (new EmptyExpression (method.ReturnType));
5850 return CreateExpressionAddCall (ec, left, expr, pos);
5853 protected override Expression DoResolve (ResolveContext ec)
5858 void Append (ResolveContext rc, Expression operand)
5863 StringConstant sc = operand as StringConstant;
5865 if (arguments.Count != 0) {
5866 Argument last_argument = arguments [arguments.Count - 1];
5867 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5868 if (last_expr_constant != null) {
5869 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5875 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5877 StringConcat concat_oper = operand as StringConcat;
5878 if (concat_oper != null) {
5879 arguments.AddRange (concat_oper.arguments);
5884 arguments.Add (new Argument (operand));
5887 IList<MemberSpec> GetConcatMethodCandidates ()
5889 return MemberCache.FindMembers (type, "Concat", true);
5892 public override void Emit (EmitContext ec)
5894 // Optimize by removing any extra null arguments, they are no-op
5895 for (int i = 0; i < arguments.Count; ++i) {
5896 if (arguments[i].Expr is NullConstant)
5897 arguments.RemoveAt (i--);
5900 var members = GetConcatMethodCandidates ();
5901 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5902 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5903 if (method != null) {
5904 var call = new CallEmitter ();
5905 call.EmitPredefined (ec, method, arguments, false);
5909 public override void FlowAnalysis (FlowAnalysisContext fc)
5911 arguments.FlowAnalysis (fc);
5914 public override SLE.Expression MakeExpression (BuilderContext ctx)
5916 if (arguments.Count != 2)
5917 throw new NotImplementedException ("arguments.Count != 2");
5919 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5920 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5925 // User-defined conditional logical operator
5927 public class ConditionalLogicalOperator : UserOperatorCall
5929 readonly bool is_and;
5930 Expression oper_expr;
5932 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5933 : base (oper, arguments, expr_tree, loc)
5935 this.is_and = is_and;
5936 eclass = ExprClass.Unresolved;
5939 protected override Expression DoResolve (ResolveContext ec)
5941 AParametersCollection pd = oper.Parameters;
5942 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5943 ec.Report.Error (217, loc,
5944 "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",
5945 oper.GetSignatureForError ());
5949 Expression left_dup = new EmptyExpression (type);
5950 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5951 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5952 if (op_true == null || op_false == null) {
5953 ec.Report.Error (218, loc,
5954 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5955 type.GetSignatureForError (), oper.GetSignatureForError ());
5959 oper_expr = is_and ? op_false : op_true;
5960 eclass = ExprClass.Value;
5964 public override void Emit (EmitContext ec)
5966 Label end_target = ec.DefineLabel ();
5969 // Emit and duplicate left argument
5971 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5972 if (right_contains_await) {
5973 arguments[0] = arguments[0].EmitToField (ec, false);
5974 arguments[0].Expr.Emit (ec);
5976 arguments[0].Expr.Emit (ec);
5977 ec.Emit (OpCodes.Dup);
5978 arguments.RemoveAt (0);
5981 oper_expr.EmitBranchable (ec, end_target, true);
5985 if (right_contains_await) {
5987 // Special handling when right expression contains await and left argument
5988 // could not be left on stack before logical branch
5990 Label skip_left_load = ec.DefineLabel ();
5991 ec.Emit (OpCodes.Br_S, skip_left_load);
5992 ec.MarkLabel (end_target);
5993 arguments[0].Expr.Emit (ec);
5994 ec.MarkLabel (skip_left_load);
5996 ec.MarkLabel (end_target);
6001 public class PointerArithmetic : Expression {
6002 Expression left, right;
6003 readonly Binary.Operator op;
6006 // We assume that `l' is always a pointer
6008 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
6017 public override bool ContainsEmitWithAwait ()
6019 throw new NotImplementedException ();
6022 public override Expression CreateExpressionTree (ResolveContext ec)
6024 Error_PointerInsideExpressionTree (ec);
6028 protected override Expression DoResolve (ResolveContext ec)
6030 eclass = ExprClass.Variable;
6032 var pc = left.Type as PointerContainer;
6033 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6034 Error_VoidPointerOperation (ec);
6041 public override void Emit (EmitContext ec)
6043 TypeSpec op_type = left.Type;
6045 // It must be either array or fixed buffer
6047 if (TypeManager.HasElementType (op_type)) {
6048 element = TypeManager.GetElementType (op_type);
6050 FieldExpr fe = left as FieldExpr;
6052 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6057 int size = BuiltinTypeSpec.GetSize(element);
6058 TypeSpec rtype = right.Type;
6060 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6062 // handle (pointer - pointer)
6066 ec.Emit (OpCodes.Sub);
6070 ec.Emit (OpCodes.Sizeof, element);
6073 ec.Emit (OpCodes.Div);
6075 ec.Emit (OpCodes.Conv_I8);
6078 // handle + and - on (pointer op int)
6080 Constant left_const = left as Constant;
6081 if (left_const != null) {
6083 // Optimize ((T*)null) pointer operations
6085 if (left_const.IsDefaultValue) {
6086 left = EmptyExpression.Null;
6094 var right_const = right as Constant;
6095 if (right_const != null) {
6097 // Optimize 0-based arithmetic
6099 if (right_const.IsDefaultValue)
6103 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6105 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6107 // TODO: Should be the checks resolve context sensitive?
6108 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6109 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6115 if (right_const == null) {
6116 switch (rtype.BuiltinType) {
6117 case BuiltinTypeSpec.Type.SByte:
6118 case BuiltinTypeSpec.Type.Byte:
6119 case BuiltinTypeSpec.Type.Short:
6120 case BuiltinTypeSpec.Type.UShort:
6121 case BuiltinTypeSpec.Type.Int:
6122 ec.Emit (OpCodes.Conv_I);
6124 case BuiltinTypeSpec.Type.UInt:
6125 ec.Emit (OpCodes.Conv_U);
6130 if (right_const == null && size != 1){
6132 ec.Emit (OpCodes.Sizeof, element);
6135 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6136 ec.Emit (OpCodes.Conv_I8);
6138 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6141 if (left_const == null) {
6142 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6143 ec.Emit (OpCodes.Conv_I);
6144 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6145 ec.Emit (OpCodes.Conv_U);
6147 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6154 // A boolean-expression is an expression that yields a result
6157 public class BooleanExpression : ShimExpression
6159 public BooleanExpression (Expression expr)
6162 this.loc = expr.Location;
6165 public override Expression CreateExpressionTree (ResolveContext ec)
6167 // TODO: We should emit IsTrue (v4) instead of direct user operator
6168 // call but that would break csc compatibility
6169 return base.CreateExpressionTree (ec);
6172 protected override Expression DoResolve (ResolveContext ec)
6174 // A boolean-expression is required to be of a type
6175 // that can be implicitly converted to bool or of
6176 // a type that implements operator true
6178 expr = expr.Resolve (ec);
6182 Assign ass = expr as Assign;
6183 if (ass != null && ass.Source is Constant) {
6184 ec.Report.Warning (665, 3, loc,
6185 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6188 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6191 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6192 Arguments args = new Arguments (1);
6193 args.Add (new Argument (expr));
6194 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6197 type = ec.BuiltinTypes.Bool;
6198 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6199 if (converted != null)
6203 // If no implicit conversion to bool exists, try using `operator true'
6205 converted = GetOperatorTrue (ec, expr, loc);
6206 if (converted == null) {
6207 expr.Error_ValueCannotBeConverted (ec, type, false);
6214 public override object Accept (StructuralVisitor visitor)
6216 return visitor.Visit (this);
6220 public class BooleanExpressionFalse : Unary
6222 public BooleanExpressionFalse (Expression expr)
6223 : base (Operator.LogicalNot, expr, expr.Location)
6227 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6229 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6234 /// Implements the ternary conditional operator (?:)
6236 public class Conditional : Expression {
6237 Expression expr, true_expr, false_expr;
6239 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6242 this.true_expr = true_expr;
6243 this.false_expr = false_expr;
6249 public Expression Expr {
6255 public Expression TrueExpr {
6261 public Expression FalseExpr {
6269 public override bool ContainsEmitWithAwait ()
6271 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6274 public override Expression CreateExpressionTree (ResolveContext ec)
6276 Arguments args = new Arguments (3);
6277 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6278 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6279 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6280 return CreateExpressionFactoryCall (ec, "Condition", args);
6283 protected override Expression DoResolve (ResolveContext ec)
6285 expr = expr.Resolve (ec);
6286 true_expr = true_expr.Resolve (ec);
6287 false_expr = false_expr.Resolve (ec);
6289 if (true_expr == null || false_expr == null || expr == null)
6292 eclass = ExprClass.Value;
6293 TypeSpec true_type = true_expr.Type;
6294 TypeSpec false_type = false_expr.Type;
6298 // First, if an implicit conversion exists from true_expr
6299 // to false_expr, then the result type is of type false_expr.Type
6301 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6302 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6303 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6305 // Check if both can convert implicitly to each other's type
6309 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6310 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6312 // LAMESPEC: There seems to be hardcoded promotition to int type when
6313 // both sides are numeric constants and one side is int constant and
6314 // other side is numeric constant convertible to int.
6316 // var res = condition ? (short)1 : 1;
6318 // Type of res is int even if according to the spec the conversion is
6319 // ambiguous because 1 literal can be converted to short.
6321 if (conv_false_expr != null) {
6322 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6324 conv_false_expr = null;
6325 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6326 conv_false_expr = null;
6330 if (conv_false_expr != null) {
6331 ec.Report.Error (172, true_expr.Location,
6332 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6333 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6338 if (true_expr.Type != type)
6339 true_expr = EmptyCast.Create (true_expr, type);
6340 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6343 if (false_type != InternalType.ErrorType) {
6344 ec.Report.Error (173, true_expr.Location,
6345 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6346 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6352 Constant c = expr as Constant;
6354 bool is_false = c.IsDefaultValue;
6357 // Don't issue the warning for constant expressions
6359 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6360 // CSC: Missing warning
6361 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6364 return ReducedExpression.Create (
6365 is_false ? false_expr : true_expr, this,
6366 false_expr is Constant && true_expr is Constant).Resolve (ec);
6372 public override void Emit (EmitContext ec)
6374 Label false_target = ec.DefineLabel ();
6375 Label end_target = ec.DefineLabel ();
6377 expr.EmitBranchable (ec, false_target, false);
6378 true_expr.Emit (ec);
6381 // Verifier doesn't support interface merging. When there are two types on
6382 // the stack without common type hint and the common type is an interface.
6383 // Use temporary local to give verifier hint on what type to unify the stack
6385 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6386 var temp = ec.GetTemporaryLocal (type);
6387 ec.Emit (OpCodes.Stloc, temp);
6388 ec.Emit (OpCodes.Ldloc, temp);
6389 ec.FreeTemporaryLocal (temp, type);
6392 ec.Emit (OpCodes.Br, end_target);
6393 ec.MarkLabel (false_target);
6394 false_expr.Emit (ec);
6395 ec.MarkLabel (end_target);
6398 public override void FlowAnalysis (FlowAnalysisContext fc)
6400 expr.FlowAnalysisConditional (fc);
6401 var expr_true = fc.DefiniteAssignmentOnTrue;
6402 var expr_false = fc.DefiniteAssignmentOnFalse;
6404 fc.BranchDefiniteAssignment (expr_true);
6405 true_expr.FlowAnalysis (fc);
6406 var true_fc = fc.DefiniteAssignment;
6408 fc.BranchDefiniteAssignment (expr_false);
6409 false_expr.FlowAnalysis (fc);
6411 fc.DefiniteAssignment &= true_fc;
6414 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6416 expr.FlowAnalysisConditional (fc);
6417 var expr_true = fc.DefiniteAssignmentOnTrue;
6418 var expr_false = fc.DefiniteAssignmentOnFalse;
6420 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6421 true_expr.FlowAnalysisConditional (fc);
6422 var true_fc = fc.DefiniteAssignment;
6423 var true_da_true = fc.DefiniteAssignmentOnTrue;
6424 var true_da_false = fc.DefiniteAssignmentOnFalse;
6426 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6427 false_expr.FlowAnalysisConditional (fc);
6429 fc.DefiniteAssignment &= true_fc;
6430 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6431 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6434 protected override void CloneTo (CloneContext clonectx, Expression t)
6436 Conditional target = (Conditional) t;
6438 target.expr = expr.Clone (clonectx);
6439 target.true_expr = true_expr.Clone (clonectx);
6440 target.false_expr = false_expr.Clone (clonectx);
6444 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6446 LocalTemporary temp;
6449 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6450 public abstract void SetHasAddressTaken ();
6452 public abstract bool IsLockedByStatement { get; set; }
6454 public abstract bool IsFixed { get; }
6455 public abstract bool IsRef { get; }
6456 public abstract string Name { get; }
6459 // Variable IL data, it has to be protected to encapsulate hoisted variables
6461 protected abstract ILocalVariable Variable { get; }
6464 // Variable flow-analysis data
6466 public abstract VariableInfo VariableInfo { get; }
6469 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6471 HoistedVariable hv = GetHoistedVariable (ec);
6473 hv.AddressOf (ec, mode);
6477 Variable.EmitAddressOf (ec);
6480 public override bool ContainsEmitWithAwait ()
6485 public override Expression CreateExpressionTree (ResolveContext ec)
6487 HoistedVariable hv = GetHoistedVariable (ec);
6489 return hv.CreateExpressionTree ();
6491 Arguments arg = new Arguments (1);
6492 arg.Add (new Argument (this));
6493 return CreateExpressionFactoryCall (ec, "Constant", arg);
6496 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6498 if (IsLockedByStatement) {
6499 rc.Report.Warning (728, 2, loc,
6500 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6507 public override void Emit (EmitContext ec)
6512 public override void EmitSideEffect (EmitContext ec)
6518 // This method is used by parameters that are references, that are
6519 // being passed as references: we only want to pass the pointer (that
6520 // is already stored in the parameter, not the address of the pointer,
6521 // and not the value of the variable).
6523 public void EmitLoad (EmitContext ec)
6528 public void Emit (EmitContext ec, bool leave_copy)
6530 HoistedVariable hv = GetHoistedVariable (ec);
6532 hv.Emit (ec, leave_copy);
6540 // If we are a reference, we loaded on the stack a pointer
6541 // Now lets load the real value
6543 ec.EmitLoadFromPtr (type);
6547 ec.Emit (OpCodes.Dup);
6550 temp = new LocalTemporary (Type);
6556 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6557 bool prepare_for_load)
6559 HoistedVariable hv = GetHoistedVariable (ec);
6561 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6565 bool dereference = IsRef && !(source is ReferenceExpression);
6566 New n_source = source as New;
6567 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6568 if (!n_source.Emit (ec, this)) {
6572 ec.EmitLoadFromPtr (type);
6584 ec.Emit (OpCodes.Dup);
6586 temp = new LocalTemporary (Type);
6592 ec.EmitStoreFromPtr (type);
6594 Variable.EmitAssign (ec);
6602 public override Expression EmitToField (EmitContext ec)
6604 HoistedVariable hv = GetHoistedVariable (ec);
6606 return hv.EmitToField (ec);
6609 return base.EmitToField (ec);
6612 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6614 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6617 public HoistedVariable GetHoistedVariable (EmitContext ec)
6619 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6622 public override string GetSignatureForError ()
6627 public bool IsHoisted {
6628 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6633 // Resolved reference to a local variable
6635 public class LocalVariableReference : VariableReference
6637 public LocalVariable local_info;
6639 public LocalVariableReference (LocalVariable li, Location l)
6641 this.local_info = li;
6645 public override VariableInfo VariableInfo {
6646 get { return local_info.VariableInfo; }
6649 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6651 return local_info.HoistedVariant;
6657 // A local variable is always fixed
6659 public override bool IsFixed {
6665 public override bool IsLockedByStatement {
6667 return local_info.IsLocked;
6670 local_info.IsLocked = value;
6674 public override bool IsRef {
6675 get { return local_info.IsByRef; }
6678 public override string Name {
6679 get { return local_info.Name; }
6684 public override void FlowAnalysis (FlowAnalysisContext fc)
6686 VariableInfo variable_info = VariableInfo;
6687 if (variable_info == null)
6690 if (fc.IsDefinitelyAssigned (variable_info))
6693 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6694 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6697 public override void SetHasAddressTaken ()
6699 local_info.SetHasAddressTaken ();
6702 void DoResolveBase (ResolveContext ec)
6704 eclass = ExprClass.Variable;
6705 type = local_info.Type;
6708 // If we are referencing a variable from the external block
6709 // flag it for capturing
6711 if (ec.MustCaptureVariable (local_info)) {
6712 if (local_info.AddressTaken) {
6713 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6714 } else if (local_info.IsFixed) {
6715 ec.Report.Error (1764, loc,
6716 "Cannot use fixed variable `{0}' inside an anonymous method, lambda expression or query expression",
6717 GetSignatureForError ());
6718 } else if (local_info.IsByRef) {
6719 ec.Report.Error (8175, loc,
6720 "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression",
6721 GetSignatureForError ());
6724 if (ec.IsVariableCapturingRequired) {
6725 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6726 storey.CaptureLocalVariable (ec, local_info);
6731 protected override Expression DoResolve (ResolveContext ec)
6733 local_info.SetIsUsed ();
6737 if (local_info.Type == InternalType.VarOutType) {
6738 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6739 GetSignatureForError ());
6741 type = InternalType.ErrorType;
6747 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6750 // Don't be too pedantic when variable is used as out param or for some broken code
6751 // which uses property/indexer access to run some initialization
6753 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6754 local_info.SetIsUsed ();
6756 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6757 if (rhs == EmptyExpression.LValueMemberAccess) {
6758 // CS1654 already reported
6762 if (rhs == EmptyExpression.OutAccess) {
6763 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6764 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6765 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6766 } else if (rhs == EmptyExpression.UnaryAddress) {
6767 code = 459; msg = "Cannot take the address of {1} `{0}'";
6769 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6771 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6775 if (eclass == ExprClass.Unresolved)
6778 return base.DoResolveLValue (ec, rhs);
6781 public override int GetHashCode ()
6783 return local_info.GetHashCode ();
6786 public override bool Equals (object obj)
6788 LocalVariableReference lvr = obj as LocalVariableReference;
6792 return local_info == lvr.local_info;
6795 protected override ILocalVariable Variable {
6796 get { return local_info; }
6799 public override string ToString ()
6801 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6804 protected override void CloneTo (CloneContext clonectx, Expression t)
6811 /// This represents a reference to a parameter in the intermediate
6814 public class ParameterReference : VariableReference
6816 protected ParametersBlock.ParameterInfo pi;
6818 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6826 public override bool IsLockedByStatement {
6831 pi.IsLocked = value;
6835 public override bool IsRef {
6836 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6839 bool HasOutModifier {
6840 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6843 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6845 return pi.Parameter.HoistedVariant;
6849 // A ref or out parameter is classified as a moveable variable, even
6850 // if the argument given for the parameter is a fixed variable
6852 public override bool IsFixed {
6853 get { return !IsRef; }
6856 public override string Name {
6857 get { return Parameter.Name; }
6860 public Parameter Parameter {
6861 get { return pi.Parameter; }
6864 public override VariableInfo VariableInfo {
6865 get { return pi.VariableInfo; }
6868 protected override ILocalVariable Variable {
6869 get { return Parameter; }
6874 public override void AddressOf (EmitContext ec, AddressOp mode)
6877 // ParameterReferences might already be a reference
6884 base.AddressOf (ec, mode);
6887 public override void SetHasAddressTaken ()
6889 Parameter.HasAddressTaken = true;
6892 bool DoResolveBase (ResolveContext ec)
6894 if (eclass != ExprClass.Unresolved)
6897 type = pi.ParameterType;
6898 eclass = ExprClass.Variable;
6901 // If we are referencing a parameter from the external block
6902 // flag it for capturing
6904 if (ec.MustCaptureVariable (pi)) {
6905 if (Parameter.HasAddressTaken)
6906 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6909 ec.Report.Error (1628, loc,
6910 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6911 Name, ec.CurrentAnonymousMethod.ContainerType);
6914 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6915 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6916 storey.CaptureParameter (ec, pi, this);
6923 public override int GetHashCode ()
6925 return Name.GetHashCode ();
6928 public override bool Equals (object obj)
6930 ParameterReference pr = obj as ParameterReference;
6934 return Name == pr.Name;
6937 protected override void CloneTo (CloneContext clonectx, Expression target)
6943 public override Expression CreateExpressionTree (ResolveContext ec)
6945 HoistedVariable hv = GetHoistedVariable (ec);
6947 return hv.CreateExpressionTree ();
6949 return Parameter.ExpressionTreeVariableReference ();
6952 protected override Expression DoResolve (ResolveContext ec)
6954 if (!DoResolveBase (ec))
6960 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6962 if (!DoResolveBase (ec))
6965 if (Parameter.HoistedVariant != null)
6966 Parameter.HoistedVariant.IsAssigned = true;
6968 return base.DoResolveLValue (ec, right_side);
6971 public override void FlowAnalysis (FlowAnalysisContext fc)
6973 VariableInfo variable_info = VariableInfo;
6974 if (variable_info == null)
6977 if (fc.IsDefinitelyAssigned (variable_info))
6980 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6981 fc.SetVariableAssigned (variable_info);
6986 /// Invocation of methods or delegates.
6988 public class Invocation : ExpressionStatement
6990 public class Predefined : Invocation
6992 public Predefined (MethodGroupExpr expr, Arguments arguments)
6993 : base (expr, arguments)
6998 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
7000 mg.BestCandidate.CheckObsoleteness (rc, loc);
7006 protected Arguments arguments;
7007 protected Expression expr;
7008 protected MethodGroupExpr mg;
7009 bool conditional_access_receiver;
7011 public Invocation (Expression expr, Arguments arguments)
7014 this.arguments = arguments;
7016 loc = expr.Location;
7021 public Arguments Arguments {
7027 public Expression Exp {
7033 public MethodGroupExpr MethodGroup {
7039 public override Location StartLocation {
7041 return expr.StartLocation;
7047 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7049 if (MethodGroup == null)
7052 var candidate = MethodGroup.BestCandidate;
7053 if (candidate == null || !(candidate.IsStatic || Exp is This))
7056 var args_count = arguments == null ? 0 : arguments.Count;
7057 if (args_count != body.Parameters.Count)
7060 var lambda_parameters = body.Block.Parameters.FixedParameters;
7061 for (int i = 0; i < args_count; ++i) {
7062 var pr = arguments[i].Expr as ParameterReference;
7066 if (lambda_parameters[i] != pr.Parameter)
7069 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7073 var emg = MethodGroup as ExtensionMethodGroupExpr;
7075 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7076 if (candidate.IsGeneric) {
7077 var targs = new TypeExpression [candidate.Arity];
7078 for (int i = 0; i < targs.Length; ++i) {
7079 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7082 mg.SetTypeArguments (null, new TypeArguments (targs));
7091 protected override void CloneTo (CloneContext clonectx, Expression t)
7093 Invocation target = (Invocation) t;
7095 if (arguments != null)
7096 target.arguments = arguments.Clone (clonectx);
7098 target.expr = expr.Clone (clonectx);
7101 public override bool ContainsEmitWithAwait ()
7103 if (arguments != null && arguments.ContainsEmitWithAwait ())
7106 return mg.ContainsEmitWithAwait ();
7109 public override Expression CreateExpressionTree (ResolveContext ec)
7111 Expression instance = mg.IsInstance ?
7112 mg.InstanceExpression.CreateExpressionTree (ec) :
7113 new NullLiteral (loc);
7115 var args = Arguments.CreateForExpressionTree (ec, arguments,
7117 mg.CreateExpressionTree (ec));
7119 return CreateExpressionFactoryCall (ec, "Call", args);
7122 void ResolveConditionalAccessReceiver (ResolveContext rc)
7124 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7125 conditional_access_receiver = true;
7129 bool statement_resolve;
7130 public override ExpressionStatement ResolveStatement (BlockContext bc)
7132 statement_resolve = true;
7133 var es = base.ResolveStatement (bc);
7134 statement_resolve = false;
7139 protected override Expression DoResolve (ResolveContext rc)
7141 ResolveConditionalAccessReceiver (rc);
7142 return DoResolveInvocation (rc, null);
7145 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7147 var sn = expr as SimpleName;
7148 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
7149 var targets = new List<Expression> (arguments.Count);
7150 var variables = new List<LocalVariable> (arguments.Count);
7151 foreach (var arg in arguments) {
7152 var arg_sn = arg.Expr as SimpleName;
7153 if (arg_sn == null || arg_sn.Arity != 0) {
7154 rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
7155 return ErrorExpression.Instance;
7158 var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
7159 rc.CurrentBlock.AddLocalName (lv);
7162 targets.Add (new LocalVariableReference (lv, arg_sn.Location));
7165 var res = new TupleDeconstruct (targets, variables, right_side, loc);
7166 return res.Resolve (rc);
7169 if (right_side != null) {
7170 if (eclass != ExprClass.Unresolved)
7173 var res = DoResolveInvocation (rc, right_side);
7180 return base.DoResolveLValue (rc, right_side);
7183 Expression DoResolveInvocation (ResolveContext ec, Expression rhs)
7185 Expression member_expr;
7186 var atn = expr as ATypeNameExpression;
7188 var flags = default (ResolveContext.FlagsHandle);
7189 if (conditional_access_receiver)
7190 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7193 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7194 if (member_expr != null) {
7195 var name_of = member_expr as NameOf;
7196 if (name_of != null) {
7197 return name_of.ResolveOverload (ec, arguments);
7200 member_expr = member_expr.Resolve (ec);
7203 member_expr = expr.Resolve (ec);
7206 if (conditional_access_receiver)
7209 if (member_expr == null)
7213 // Next, evaluate all the expressions in the argument list
7215 bool dynamic_arg = false;
7216 if (arguments != null) {
7217 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7218 arguments.Resolve (ec, out dynamic_arg);
7222 TypeSpec expr_type = member_expr.Type;
7223 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7224 return DoResolveDynamic (ec, member_expr);
7226 mg = member_expr as MethodGroupExpr;
7227 Expression invoke = null;
7230 if (expr_type != null && expr_type.IsDelegate) {
7231 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7232 invoke = invoke.Resolve (ec);
7233 if (invoke == null || !dynamic_arg)
7236 if (member_expr is RuntimeValueExpression) {
7237 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7238 member_expr.Type.GetSignatureForError ());
7242 MemberExpr me = member_expr as MemberExpr;
7244 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7248 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7249 member_expr.GetSignatureForError ());
7254 if (invoke == null) {
7255 mg = DoResolveOverload (ec);
7261 return DoResolveDynamic (ec, member_expr);
7263 var method = mg.BestCandidate;
7264 type = mg.BestCandidateReturnType;
7265 if (conditional_access_receiver && !statement_resolve)
7266 type = LiftMemberType (ec, type);
7268 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7270 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7272 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7276 IsSpecialMethodInvocation (ec, method, loc);
7278 eclass = ExprClass.Value;
7280 if (type.Kind == MemberKind.ByRef) {
7281 if (rhs == null && arguments?.ContainsEmitWithAwait () == true) {
7282 ec.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
7283 GetSignatureForError ());
7286 if (rhs != EmptyExpression.OutAccess)
7287 return ByRefDereference.Create (this).Resolve (ec);
7293 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7296 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7298 args = dmb.Arguments;
7299 if (arguments != null)
7300 args.AddRange (arguments);
7301 } else if (mg == null) {
7302 if (arguments == null)
7303 args = new Arguments (1);
7307 args.Insert (0, new Argument (memberExpr));
7311 ec.Report.Error (1971, loc,
7312 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7317 if (arguments == null)
7318 args = new Arguments (1);
7322 MemberAccess ma = expr as MemberAccess;
7324 var inst = mg.InstanceExpression;
7325 var left_type = inst as TypeExpr;
7326 if (left_type != null) {
7327 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7328 } else if (inst != null) {
7330 // Any value type has to be pass as by-ref to get back the same
7331 // instance on which the member was called
7333 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7334 Argument.AType.Ref : Argument.AType.None;
7335 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7337 } else { // is SimpleName
7338 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7339 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7341 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7346 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7349 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7351 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7354 public override void FlowAnalysis (FlowAnalysisContext fc)
7356 if (mg.IsConditionallyExcluded)
7359 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7361 mg.FlowAnalysis (fc);
7363 if (arguments != null)
7364 arguments.FlowAnalysis (fc);
7366 if (conditional_access_receiver)
7367 fc.DefiniteAssignment = da;
7370 public override string GetSignatureForError ()
7372 return mg.GetSignatureForError ();
7375 public override bool HasConditionalAccess ()
7377 return expr.HasConditionalAccess ();
7381 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7382 // or the type dynamic, then the member is invocable
7384 public static bool IsMemberInvocable (MemberSpec member)
7386 switch (member.Kind) {
7387 case MemberKind.Event:
7389 case MemberKind.Field:
7390 case MemberKind.Property:
7391 var m = member as IInterfaceMemberSpec;
7392 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7398 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7400 if (!method.IsReservedMethod)
7403 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7406 ec.Report.SymbolRelatedToPreviousError (method);
7407 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7408 method.GetSignatureForError ());
7413 public override void Emit (EmitContext ec)
7415 if (mg.IsConditionallyExcluded)
7418 if (conditional_access_receiver)
7419 mg.EmitCall (ec, arguments, type, false);
7421 mg.EmitCall (ec, arguments, false);
7424 public override void EmitPrepare (EmitContext ec)
7426 mg.EmitPrepare (ec);
7428 arguments?.EmitPrepare (ec);
7431 public override void EmitStatement (EmitContext ec)
7433 if (mg.IsConditionallyExcluded)
7436 if (conditional_access_receiver)
7437 mg.EmitCall (ec, arguments, type, true);
7439 mg.EmitCall (ec, arguments, true);
7442 public override SLE.Expression MakeExpression (BuilderContext ctx)
7444 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7447 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7450 throw new NotSupportedException ();
7452 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7453 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7457 public override object Accept (StructuralVisitor visitor)
7459 return visitor.Visit (this);
7464 // Implements simple new expression
7466 public class New : ExpressionStatement, IMemoryLocation
7468 protected Arguments arguments;
7471 // During bootstrap, it contains the RequestedType,
7472 // but if `type' is not null, it *might* contain a NewDelegate
7473 // (because of field multi-initialization)
7475 protected Expression RequestedType;
7477 protected MethodSpec method;
7479 public New (Expression requested_type, Arguments arguments, Location l)
7481 RequestedType = requested_type;
7482 this.arguments = arguments;
7487 public Arguments Arguments {
7494 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7496 public bool IsGeneratedStructConstructor {
7498 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7502 public Expression TypeExpression {
7504 return RequestedType;
7511 /// Converts complex core type syntax like 'new int ()' to simple constant
7513 public static Constant Constantify (TypeSpec t, Location loc)
7515 switch (t.BuiltinType) {
7516 case BuiltinTypeSpec.Type.Int:
7517 return new IntConstant (t, 0, loc);
7518 case BuiltinTypeSpec.Type.UInt:
7519 return new UIntConstant (t, 0, loc);
7520 case BuiltinTypeSpec.Type.Long:
7521 return new LongConstant (t, 0, loc);
7522 case BuiltinTypeSpec.Type.ULong:
7523 return new ULongConstant (t, 0, loc);
7524 case BuiltinTypeSpec.Type.Float:
7525 return new FloatConstant (t, 0, loc);
7526 case BuiltinTypeSpec.Type.Double:
7527 return new DoubleConstant (t, 0, loc);
7528 case BuiltinTypeSpec.Type.Short:
7529 return new ShortConstant (t, 0, loc);
7530 case BuiltinTypeSpec.Type.UShort:
7531 return new UShortConstant (t, 0, loc);
7532 case BuiltinTypeSpec.Type.SByte:
7533 return new SByteConstant (t, 0, loc);
7534 case BuiltinTypeSpec.Type.Byte:
7535 return new ByteConstant (t, 0, loc);
7536 case BuiltinTypeSpec.Type.Char:
7537 return new CharConstant (t, '\0', loc);
7538 case BuiltinTypeSpec.Type.Bool:
7539 return new BoolConstant (t, false, loc);
7540 case BuiltinTypeSpec.Type.Decimal:
7541 return new DecimalConstant (t, 0, loc);
7545 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7547 if (t.IsNullableType)
7548 return Nullable.LiftedNull.Create (t, loc);
7553 public override bool ContainsEmitWithAwait ()
7555 return arguments != null && arguments.ContainsEmitWithAwait ();
7559 // Checks whether the type is an interface that has the
7560 // [ComImport, CoClass] attributes and must be treated
7563 public Expression CheckComImport (ResolveContext ec)
7565 if (!type.IsInterface)
7569 // Turn the call into:
7570 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7572 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7573 if (real_class == null)
7576 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7577 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7578 return cast.Resolve (ec);
7581 public override Expression CreateExpressionTree (ResolveContext ec)
7584 if (method == null) {
7585 args = new Arguments (1);
7586 args.Add (new Argument (new TypeOf (type, loc)));
7588 args = Arguments.CreateForExpressionTree (ec,
7589 arguments, new TypeOfMethod (method, loc));
7592 return CreateExpressionFactoryCall (ec, "New", args);
7595 protected override Expression DoResolve (ResolveContext ec)
7597 if (RequestedType is TupleTypeExpr) {
7598 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
7601 type = RequestedType.ResolveAsType (ec);
7605 eclass = ExprClass.Value;
7607 if (type.IsPointer) {
7608 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7609 type.GetSignatureForError ());
7613 if (arguments == null) {
7614 Constant c = Constantify (type, RequestedType.Location);
7616 return ReducedExpression.Create (c, this);
7619 if (type.IsDelegate) {
7620 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7623 var tparam = type as TypeParameterSpec;
7624 if (tparam != null) {
7626 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7627 // where type parameter constraint is inflated to struct
7629 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7630 ec.Report.Error (304, loc,
7631 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7632 type.GetSignatureForError ());
7635 if ((arguments != null) && (arguments.Count != 0)) {
7636 ec.Report.Error (417, loc,
7637 "`{0}': cannot provide arguments when creating an instance of a variable type",
7638 type.GetSignatureForError ());
7644 if (type.IsStatic) {
7645 ec.Report.SymbolRelatedToPreviousError (type);
7646 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7650 if (type.IsInterface || type.IsAbstract){
7651 if (!TypeManager.IsGenericType (type)) {
7652 RequestedType = CheckComImport (ec);
7653 if (RequestedType != null)
7654 return RequestedType;
7657 ec.Report.SymbolRelatedToPreviousError (type);
7658 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7663 if (arguments != null) {
7664 arguments.Resolve (ec, out dynamic);
7669 method = ConstructorLookup (ec, type, ref arguments, loc);
7672 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7673 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7679 void DoEmitTypeParameter (EmitContext ec)
7681 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7685 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7686 ec.Emit (OpCodes.Call, ctor_factory);
7690 // This Emit can be invoked in two contexts:
7691 // * As a mechanism that will leave a value on the stack (new object)
7692 // * As one that wont (init struct)
7694 // If we are dealing with a ValueType, we have a few
7695 // situations to deal with:
7697 // * The target is a ValueType, and we have been provided
7698 // the instance (this is easy, we are being assigned).
7700 // * The target of New is being passed as an argument,
7701 // to a boxing operation or a function that takes a
7704 // In this case, we need to create a temporary variable
7705 // that is the argument of New.
7707 // Returns whether a value is left on the stack
7709 // *** Implementation note ***
7711 // To benefit from this optimization, each assignable expression
7712 // has to manually cast to New and call this Emit.
7714 // TODO: It's worth to implement it for arrays and fields
7716 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7718 bool is_value_type = type.IsStructOrEnum;
7719 VariableReference vr = target as VariableReference;
7721 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7723 if (target != null && is_value_type && (vr != null || method == null)) {
7724 if (prepare_await) {
7725 arguments = arguments.Emit (ec, false, true);
7726 prepare_await = false;
7729 target.AddressOf (ec, AddressOp.Store);
7730 } else if (vr != null && vr.IsRef) {
7734 if (arguments != null) {
7736 arguments = arguments.Emit (ec, false, true);
7738 arguments.Emit (ec);
7741 if (is_value_type) {
7742 if (method == null) {
7743 ec.Emit (OpCodes.Initobj, type);
7748 ec.MarkCallEntry (loc);
7749 ec.Emit (OpCodes.Call, method);
7754 if (type is TypeParameterSpec) {
7755 DoEmitTypeParameter (ec);
7759 ec.MarkCallEntry (loc);
7760 ec.Emit (OpCodes.Newobj, method);
7764 public override void Emit (EmitContext ec)
7766 LocalTemporary v = null;
7767 if (method == null && type.IsStructOrEnum) {
7768 // TODO: Use temporary variable from pool
7769 v = new LocalTemporary (type);
7776 public override void EmitStatement (EmitContext ec)
7778 LocalTemporary v = null;
7779 if (method == null && TypeSpec.IsValueType (type)) {
7780 // TODO: Use temporary variable from pool
7781 v = new LocalTemporary (type);
7785 ec.Emit (OpCodes.Pop);
7788 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7793 public override void FlowAnalysis (FlowAnalysisContext fc)
7795 if (arguments != null)
7796 arguments.FlowAnalysis (fc);
7799 public void AddressOf (EmitContext ec, AddressOp mode)
7801 EmitAddressOf (ec, mode);
7804 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7806 LocalTemporary value_target = new LocalTemporary (type);
7808 if (type is TypeParameterSpec) {
7809 DoEmitTypeParameter (ec);
7810 value_target.Store (ec);
7811 value_target.AddressOf (ec, mode);
7812 return value_target;
7815 value_target.AddressOf (ec, AddressOp.Store);
7817 if (method == null) {
7818 ec.Emit (OpCodes.Initobj, type);
7820 if (arguments != null)
7821 arguments.Emit (ec);
7823 ec.Emit (OpCodes.Call, method);
7826 value_target.AddressOf (ec, mode);
7827 return value_target;
7830 protected override void CloneTo (CloneContext clonectx, Expression t)
7832 New target = (New) t;
7834 target.RequestedType = RequestedType.Clone (clonectx);
7835 if (arguments != null){
7836 target.arguments = arguments.Clone (clonectx);
7840 public override SLE.Expression MakeExpression (BuilderContext ctx)
7843 return base.MakeExpression (ctx);
7845 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7849 public override object Accept (StructuralVisitor visitor)
7851 return visitor.Visit (this);
7856 // Array initializer expression, the expression is allowed in
7857 // variable or field initialization only which makes it tricky as
7858 // the type has to be infered based on the context either from field
7859 // type or variable type (think of multiple declarators)
7861 public class ArrayInitializer : Expression
7863 List<Expression> elements;
7864 BlockVariable variable;
7866 public ArrayInitializer (List<Expression> init, Location loc)
7872 public ArrayInitializer (int count, Location loc)
7873 : this (new List<Expression> (count), loc)
7877 public ArrayInitializer (Location loc)
7885 get { return elements.Count; }
7888 public List<Expression> Elements {
7894 public Expression this [int index] {
7896 return elements [index];
7900 public BlockVariable VariableDeclaration {
7911 public void Add (Expression expr)
7913 elements.Add (expr);
7916 public override bool ContainsEmitWithAwait ()
7918 throw new NotSupportedException ();
7921 public override Expression CreateExpressionTree (ResolveContext ec)
7923 throw new NotSupportedException ("ET");
7926 protected override void CloneTo (CloneContext clonectx, Expression t)
7928 var target = (ArrayInitializer) t;
7930 target.elements = new List<Expression> (elements.Count);
7931 foreach (var element in elements)
7932 target.elements.Add (element.Clone (clonectx));
7935 protected override Expression DoResolve (ResolveContext rc)
7937 var current_field = rc.CurrentMemberDefinition as FieldBase;
7938 TypeExpression type;
7939 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7940 type = new TypeExpression (current_field.MemberType, current_field.Location);
7941 } else if (variable != null) {
7942 if (variable.TypeExpression is VarExpr) {
7943 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7944 return EmptyExpression.Null;
7947 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7949 throw new NotImplementedException ("Unexpected array initializer context");
7952 return new ArrayCreation (type, this).Resolve (rc);
7955 public override void Emit (EmitContext ec)
7957 throw new InternalErrorException ("Missing Resolve call");
7960 public override void FlowAnalysis (FlowAnalysisContext fc)
7962 throw new InternalErrorException ("Missing Resolve call");
7965 public override object Accept (StructuralVisitor visitor)
7967 return visitor.Visit (this);
7972 /// 14.5.10.2: Represents an array creation expression.
7976 /// There are two possible scenarios here: one is an array creation
7977 /// expression that specifies the dimensions and optionally the
7978 /// initialization data and the other which does not need dimensions
7979 /// specified but where initialization data is mandatory.
7981 public class ArrayCreation : Expression
7983 FullNamedExpression requested_base_type;
7984 ArrayInitializer initializers;
7987 // The list of Argument types.
7988 // This is used to construct the `newarray' or constructor signature
7990 protected List<Expression> arguments;
7992 protected TypeSpec array_element_type;
7994 protected int dimensions;
7995 protected readonly ComposedTypeSpecifier rank;
7996 Expression first_emit;
7997 LocalTemporary first_emit_temp;
7999 protected List<Expression> array_data;
8001 Dictionary<int, int> bounds;
8004 // The number of constants in array initializers
8005 int const_initializers_count;
8006 bool only_constant_initializers;
8008 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
8009 : this (requested_base_type, rank, initializers, l)
8011 arguments = new List<Expression> (exprs);
8012 num_arguments = arguments.Count;
8016 // For expressions like int[] foo = new int[] { 1, 2, 3 };
8018 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8020 this.requested_base_type = requested_base_type;
8022 this.initializers = initializers;
8026 num_arguments = rank.Dimension;
8030 // For compiler generated single dimensional arrays only
8032 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
8033 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
8038 // For expressions like int[] foo = { 1, 2, 3 };
8040 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
8041 : this (requested_base_type, null, initializers, initializers.Location)
8045 public bool NoEmptyInterpolation { get; set; }
8047 public ComposedTypeSpecifier Rank {
8053 public FullNamedExpression TypeExpression {
8055 return this.requested_base_type;
8059 public ArrayInitializer Initializers {
8061 return this.initializers;
8065 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
8067 if (initializers != null && bounds == null) {
8069 // We use this to store all the data values in the order in which we
8070 // will need to store them in the byte blob later
8072 array_data = new List<Expression> (probe.Count);
8073 bounds = new Dictionary<int, int> ();
8076 if (specified_dims) {
8077 Expression a = arguments [idx];
8082 a = ConvertExpressionToArrayIndex (ec, a);
8088 if (initializers != null) {
8089 Constant c = a as Constant;
8090 if (c == null && a is ArrayIndexCast)
8091 c = ((ArrayIndexCast) a).Child as Constant;
8094 ec.Report.Error (150, a.Location, "A constant value is expected");
8100 value = System.Convert.ToInt32 (c.GetValue ());
8102 ec.Report.Error (150, a.Location, "A constant value is expected");
8106 // TODO: probe.Count does not fit ulong in
8107 if (value != probe.Count) {
8108 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8112 bounds[idx] = value;
8116 if (initializers == null)
8119 for (int i = 0; i < probe.Count; ++i) {
8121 if (o is ArrayInitializer) {
8122 var sub_probe = o as ArrayInitializer;
8123 if (idx + 1 >= dimensions){
8124 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8128 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8129 if (!bounds.ContainsKey(idx + 1))
8130 bounds[idx + 1] = sub_probe.Count;
8132 if (bounds[idx + 1] != sub_probe.Count) {
8133 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8137 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8140 } else if (child_bounds > 1) {
8141 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8143 Expression element = ResolveArrayElement (ec, o);
8144 if (element == null)
8147 // Initializers with the default values can be ignored
8148 Constant c = element as Constant;
8150 if (!c.IsDefaultInitializer (array_element_type)) {
8151 ++const_initializers_count;
8154 only_constant_initializers = false;
8157 array_data.Add (element);
8164 public override bool ContainsEmitWithAwait ()
8166 foreach (var arg in arguments) {
8167 if (arg.ContainsEmitWithAwait ())
8171 return InitializersContainAwait ();
8174 public override Expression CreateExpressionTree (ResolveContext ec)
8178 if (array_data == null) {
8179 args = new Arguments (arguments.Count + 1);
8180 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8181 foreach (Expression a in arguments)
8182 args.Add (new Argument (a.CreateExpressionTree (ec)));
8184 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8187 if (dimensions > 1) {
8188 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8192 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8193 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8194 if (array_data != null) {
8195 for (int i = 0; i < array_data.Count; ++i) {
8196 Expression e = array_data [i];
8197 args.Add (new Argument (e.CreateExpressionTree (ec)));
8201 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8204 void UpdateIndices (ResolveContext rc)
8207 for (var probe = initializers; probe != null;) {
8208 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8210 bounds[i++] = probe.Count;
8212 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8213 probe = (ArrayInitializer) probe[0];
8214 } else if (dimensions > i) {
8222 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8224 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8227 public override void FlowAnalysis (FlowAnalysisContext fc)
8229 foreach (var arg in arguments)
8230 arg.FlowAnalysis (fc);
8232 if (array_data != null) {
8233 foreach (var ad in array_data)
8234 ad.FlowAnalysis (fc);
8238 bool InitializersContainAwait ()
8240 if (array_data == null)
8243 foreach (var expr in array_data) {
8244 if (expr.ContainsEmitWithAwait ())
8251 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8253 element = element.Resolve (ec);
8254 if (element == null)
8257 var te = element as CompoundAssign.TargetExpression;
8259 for (int i = 1; i < initializers.Count; ++i) {
8260 if (initializers [i].ContainsEmitWithAwait ()) {
8261 te.RequiresEmitWithAwait = true;
8266 if (!te.RequiresEmitWithAwait) {
8267 if (first_emit != null)
8268 throw new InternalErrorException ("Can only handle one mutator at a time");
8269 first_emit = element;
8270 element = first_emit_temp = new LocalTemporary (element.Type);
8274 return Convert.ImplicitConversionRequired (
8275 ec, element, array_element_type, loc);
8278 protected bool ResolveInitializers (ResolveContext ec)
8281 only_constant_initializers = true;
8284 if (arguments != null) {
8286 for (int i = 0; i < arguments.Count; ++i) {
8287 res &= CheckIndices (ec, initializers, i, true, dimensions);
8288 if (initializers != null)
8295 arguments = new List<Expression> ();
8297 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8306 // Resolved the type of the array
8308 bool ResolveArrayType (ResolveContext ec)
8313 FullNamedExpression array_type_expr;
8314 if (num_arguments > 0) {
8315 array_type_expr = new ComposedCast (requested_base_type, rank);
8317 array_type_expr = requested_base_type;
8320 type = array_type_expr.ResolveAsType (ec);
8321 if (array_type_expr == null)
8324 var ac = type as ArrayContainer;
8326 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8330 array_element_type = ac.Element;
8331 dimensions = ac.Rank;
8336 protected override Expression DoResolve (ResolveContext ec)
8341 if (!ResolveArrayType (ec))
8345 // validate the initializers and fill in any missing bits
8347 if (!ResolveInitializers (ec))
8350 eclass = ExprClass.Value;
8354 byte [] MakeByteBlob ()
8359 int count = array_data.Count;
8361 TypeSpec element_type = array_element_type;
8362 if (element_type.IsEnum)
8363 element_type = EnumSpec.GetUnderlyingType (element_type);
8365 factor = BuiltinTypeSpec.GetSize (element_type);
8367 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8369 data = new byte [(count * factor + 3) & ~3];
8372 for (int i = 0; i < count; ++i) {
8373 var c = array_data[i] as Constant;
8379 object v = c.GetValue ();
8381 switch (element_type.BuiltinType) {
8382 case BuiltinTypeSpec.Type.Long:
8383 long lval = (long) v;
8385 for (int j = 0; j < factor; ++j) {
8386 data[idx + j] = (byte) (lval & 0xFF);
8390 case BuiltinTypeSpec.Type.ULong:
8391 ulong ulval = (ulong) v;
8393 for (int j = 0; j < factor; ++j) {
8394 data[idx + j] = (byte) (ulval & 0xFF);
8395 ulval = (ulval >> 8);
8398 case BuiltinTypeSpec.Type.Float:
8399 var fval = SingleConverter.SingleToInt32Bits((float) v);
8401 data[idx] = (byte) (fval & 0xff);
8402 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8403 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8404 data[idx + 3] = (byte) (fval >> 24);
8406 case BuiltinTypeSpec.Type.Double:
8407 element = BitConverter.GetBytes ((double) v);
8409 for (int j = 0; j < factor; ++j)
8410 data[idx + j] = element[j];
8412 // FIXME: Handle the ARM float format.
8413 if (!BitConverter.IsLittleEndian)
8414 System.Array.Reverse (data, idx, 8);
8416 case BuiltinTypeSpec.Type.Char:
8417 int chval = (int) ((char) v);
8419 data[idx] = (byte) (chval & 0xff);
8420 data[idx + 1] = (byte) (chval >> 8);
8422 case BuiltinTypeSpec.Type.Short:
8423 int sval = (int) ((short) v);
8425 data[idx] = (byte) (sval & 0xff);
8426 data[idx + 1] = (byte) (sval >> 8);
8428 case BuiltinTypeSpec.Type.UShort:
8429 int usval = (int) ((ushort) v);
8431 data[idx] = (byte) (usval & 0xff);
8432 data[idx + 1] = (byte) (usval >> 8);
8434 case BuiltinTypeSpec.Type.Int:
8437 data[idx] = (byte) (val & 0xff);
8438 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8439 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8440 data[idx + 3] = (byte) (val >> 24);
8442 case BuiltinTypeSpec.Type.UInt:
8443 uint uval = (uint) v;
8445 data[idx] = (byte) (uval & 0xff);
8446 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8447 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8448 data[idx + 3] = (byte) (uval >> 24);
8450 case BuiltinTypeSpec.Type.SByte:
8451 data[idx] = (byte) (sbyte) v;
8453 case BuiltinTypeSpec.Type.Byte:
8454 data[idx] = (byte) v;
8456 case BuiltinTypeSpec.Type.Bool:
8457 data[idx] = (byte) ((bool) v ? 1 : 0);
8459 case BuiltinTypeSpec.Type.Decimal:
8460 int[] bits = Decimal.GetBits ((decimal) v);
8463 // FIXME: For some reason, this doesn't work on the MS runtime.
8464 int[] nbits = new int[4];
8470 for (int j = 0; j < 4; j++) {
8471 data[p++] = (byte) (nbits[j] & 0xff);
8472 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8473 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8474 data[p++] = (byte) (nbits[j] >> 24);
8478 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8487 public override SLE.Expression MakeExpression (BuilderContext ctx)
8490 return base.MakeExpression (ctx);
8492 var initializers = new SLE.Expression [array_data.Count];
8493 for (var i = 0; i < initializers.Length; i++) {
8494 if (array_data [i] == null)
8495 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8497 initializers [i] = array_data [i].MakeExpression (ctx);
8500 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8505 // Emits the initializers for the array
8507 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8509 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8514 // First, the static data
8516 byte [] data = MakeByteBlob ();
8517 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8519 if (stackArray == null) {
8520 ec.Emit (OpCodes.Dup);
8522 stackArray.Emit (ec);
8525 ec.Emit (OpCodes.Ldtoken, fb);
8526 ec.Emit (OpCodes.Call, m);
8531 // Emits pieces of the array that can not be computed at compile
8532 // time (variables and string locations).
8534 // This always expect the top value on the stack to be the array
8536 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8538 int dims = bounds.Count;
8539 var current_pos = new int [dims];
8541 for (int i = 0; i < array_data.Count; i++){
8543 Expression e = array_data [i];
8544 var c = e as Constant;
8546 // Constant can be initialized via StaticInitializer
8547 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8551 if (stackArray != null) {
8552 if (e.ContainsEmitWithAwait ()) {
8553 e = e.EmitToField (ec);
8556 stackArray.EmitLoad (ec);
8558 ec.Emit (OpCodes.Dup);
8561 for (int idx = 0; idx < dims; idx++)
8562 ec.EmitInt (current_pos [idx]);
8565 // If we are dealing with a struct, get the
8566 // address of it, so we can store it.
8568 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8569 ec.Emit (OpCodes.Ldelema, etype);
8573 ec.EmitArrayStore ((ArrayContainer) type);
8579 for (int j = dims - 1; j >= 0; j--){
8581 if (current_pos [j] < bounds [j])
8583 current_pos [j] = 0;
8587 if (stackArray != null)
8588 stackArray.PrepareCleanup (ec);
8591 public override void Emit (EmitContext ec)
8593 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8596 var await_field = EmitToFieldSource (ec);
8597 if (await_field != null)
8598 await_field.Emit (ec);
8601 bool EmitOptimizedEmpty (EmitContext ec)
8603 if (arguments.Count != 1 || dimensions != 1)
8606 var c = arguments [0] as Constant;
8607 if (c == null || !c.IsZeroInteger)
8610 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8611 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8614 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8615 ec.Emit (OpCodes.Call, m);
8619 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8621 if (first_emit != null) {
8622 first_emit.Emit (ec);
8623 first_emit_temp.Store (ec);
8626 StackFieldExpr await_stack_field;
8627 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8628 await_stack_field = ec.GetTemporaryField (type);
8631 await_stack_field = null;
8634 EmitExpressionsList (ec, arguments);
8636 ec.EmitArrayNew ((ArrayContainer) type);
8638 if (initializers == null)
8639 return await_stack_field;
8641 if (await_stack_field != null)
8642 await_stack_field.EmitAssignFromStack (ec);
8646 // Emit static initializer for arrays which contain more than 2 items and
8647 // the static initializer will initialize at least 25% of array values or there
8648 // is more than 10 items to be initialized
8650 // NOTE: const_initializers_count does not contain default constant values.
8652 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8653 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8654 EmitStaticInitializers (ec, await_stack_field);
8656 if (!only_constant_initializers)
8657 EmitDynamicInitializers (ec, false, await_stack_field);
8661 EmitDynamicInitializers (ec, true, await_stack_field);
8664 if (first_emit_temp != null)
8665 first_emit_temp.Release (ec);
8667 return await_stack_field;
8670 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8672 // no multi dimensional or jagged arrays
8673 if (arguments.Count != 1 || array_element_type.IsArray) {
8674 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8678 // No array covariance, except for array -> object
8679 if (type != targetType) {
8680 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8681 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8685 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8686 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8691 // Single dimensional array of 0 size
8692 if (array_data == null) {
8693 IntConstant ic = arguments[0] as IntConstant;
8694 if (ic == null || !ic.IsDefaultValue) {
8695 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8703 enc.Encode (array_data.Count);
8704 foreach (var element in array_data) {
8705 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8709 protected override void CloneTo (CloneContext clonectx, Expression t)
8711 ArrayCreation target = (ArrayCreation) t;
8713 if (requested_base_type != null)
8714 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8716 if (arguments != null){
8717 target.arguments = new List<Expression> (arguments.Count);
8718 foreach (Expression e in arguments)
8719 target.arguments.Add (e.Clone (clonectx));
8722 if (initializers != null)
8723 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8726 public override object Accept (StructuralVisitor visitor)
8728 return visitor.Visit (this);
8733 // Represents an implicitly typed array epxression
8735 class ImplicitlyTypedArrayCreation : ArrayCreation
8737 TypeInferenceContext best_type_inference;
8739 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8740 : base (null, rank, initializers, loc)
8744 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8745 : base (null, initializers, loc)
8749 protected override Expression DoResolve (ResolveContext ec)
8754 dimensions = rank.Dimension;
8756 best_type_inference = new TypeInferenceContext ();
8758 if (!ResolveInitializers (ec))
8761 best_type_inference.FixAllTypes (ec);
8762 array_element_type = best_type_inference.InferredTypeArguments[0];
8763 best_type_inference = null;
8765 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
8766 ec.Report.Error (826, loc,
8767 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8772 // At this point we found common base type for all initializer elements
8773 // but we have to be sure that all static initializer elements are of
8776 UnifyInitializerElement (ec);
8778 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8779 eclass = ExprClass.Value;
8784 // Converts static initializer only
8786 void UnifyInitializerElement (ResolveContext ec)
8788 for (int i = 0; i < array_data.Count; ++i) {
8789 Expression e = array_data[i];
8791 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8795 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8797 element = element.Resolve (ec);
8798 if (element != null)
8799 best_type_inference.AddCommonTypeBound (element.Type);
8805 sealed class CompilerGeneratedThis : This
8807 public CompilerGeneratedThis (TypeSpec type, Location loc)
8813 protected override Expression DoResolve (ResolveContext rc)
8815 eclass = ExprClass.Variable;
8817 var block = rc.CurrentBlock;
8818 if (block != null) {
8819 var top = block.ParametersBlock.TopBlock;
8820 if (top.ThisVariable != null)
8821 variable_info = top.ThisVariable.VariableInfo;
8828 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8830 return DoResolve (rc);
8833 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8840 /// Represents the `this' construct
8843 public class This : VariableReference
8845 sealed class ThisVariable : ILocalVariable
8847 public static readonly ILocalVariable Instance = new ThisVariable ();
8849 public void Emit (EmitContext ec)
8854 public void EmitAssign (EmitContext ec)
8856 throw new InvalidOperationException ();
8859 public void EmitAddressOf (EmitContext ec)
8865 protected VariableInfo variable_info;
8867 public This (Location loc)
8874 public override string Name {
8875 get { return "this"; }
8878 public override bool IsLockedByStatement {
8886 public override bool IsRef {
8887 get { return type.IsStruct; }
8890 public override bool IsSideEffectFree {
8896 protected override ILocalVariable Variable {
8897 get { return ThisVariable.Instance; }
8900 public override VariableInfo VariableInfo {
8901 get { return variable_info; }
8904 public override bool IsFixed {
8905 get { return false; }
8910 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8913 // It's null for all cases when we don't need to check `this'
8914 // definitive assignment
8916 if (variable_info == null)
8919 if (fc.IsDefinitelyAssigned (variable_info))
8922 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8925 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8927 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8928 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8929 } else if (ec.CurrentAnonymousMethod != null) {
8930 ec.Report.Error (1673, loc,
8931 "Anonymous methods inside structs cannot access instance members of `this'. " +
8932 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8934 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8938 public override void FlowAnalysis (FlowAnalysisContext fc)
8940 CheckStructThisDefiniteAssignment (fc);
8943 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8948 AnonymousMethodStorey storey = ae.Storey;
8949 return storey != null ? storey.HoistedThis : null;
8952 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8954 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8957 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8960 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8966 public virtual void ResolveBase (ResolveContext ec)
8968 eclass = ExprClass.Variable;
8969 type = ec.CurrentType;
8971 if (!IsThisAvailable (ec, false)) {
8972 Error_ThisNotAvailable (ec);
8976 var block = ec.CurrentBlock;
8977 if (block != null) {
8978 var top = block.ParametersBlock.TopBlock;
8979 if (top.ThisVariable != null)
8980 variable_info = top.ThisVariable.VariableInfo;
8982 AnonymousExpression am = ec.CurrentAnonymousMethod;
8983 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8985 // Hoisted this is almost like hoisted variable but not exactly. When
8986 // there is no variable hoisted we can simply emit an instance method
8987 // without lifting this into a storey. Unfotunatelly this complicates
8988 // things in other cases because we don't know where this will be hoisted
8989 // until top-level block is fully resolved
8991 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8992 am.SetHasThisAccess ();
8997 protected override Expression DoResolve (ResolveContext ec)
9003 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9005 if (eclass == ExprClass.Unresolved)
9008 if (type.IsClass || type.IsReadOnly) {
9009 if (right_side == EmptyExpression.UnaryAddress)
9010 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
9011 else if (right_side == EmptyExpression.OutAccess)
9012 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
9014 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
9020 public override int GetHashCode()
9022 throw new NotImplementedException ();
9025 public override bool Equals (object obj)
9027 This t = obj as This;
9034 protected override void CloneTo (CloneContext clonectx, Expression t)
9039 public override void SetHasAddressTaken ()
9044 public override object Accept (StructuralVisitor visitor)
9046 return visitor.Visit (this);
9051 /// Represents the `__arglist' construct
9053 public class ArglistAccess : Expression
9055 public ArglistAccess (Location loc)
9060 protected override void CloneTo (CloneContext clonectx, Expression target)
9065 public override bool ContainsEmitWithAwait ()
9070 public override Expression CreateExpressionTree (ResolveContext ec)
9072 throw new NotSupportedException ("ET");
9075 protected override Expression DoResolve (ResolveContext ec)
9077 eclass = ExprClass.Variable;
9078 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
9080 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
9081 ec.Report.Error (190, loc,
9082 "The __arglist construct is valid only within a variable argument method");
9088 public override void Emit (EmitContext ec)
9090 ec.Emit (OpCodes.Arglist);
9093 public override object Accept (StructuralVisitor visitor)
9095 return visitor.Visit (this);
9100 /// Represents the `__arglist (....)' construct
9102 public class Arglist : Expression
9104 Arguments arguments;
9106 public Arglist (Location loc)
9111 public Arglist (Arguments args, Location l)
9117 public Arguments Arguments {
9123 public MetaType[] ArgumentTypes {
9125 if (arguments == null)
9126 return MetaType.EmptyTypes;
9128 var retval = new MetaType[arguments.Count];
9129 for (int i = 0; i < retval.Length; i++)
9130 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9136 public override bool ContainsEmitWithAwait ()
9138 throw new NotImplementedException ();
9141 public override Expression CreateExpressionTree (ResolveContext ec)
9143 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9147 protected override Expression DoResolve (ResolveContext ec)
9149 eclass = ExprClass.Variable;
9150 type = InternalType.Arglist;
9151 if (arguments != null) {
9152 bool dynamic; // Can be ignored as there is always only 1 overload
9153 arguments.Resolve (ec, out dynamic);
9159 public override void Emit (EmitContext ec)
9161 if (arguments != null)
9162 arguments.Emit (ec);
9165 protected override void CloneTo (CloneContext clonectx, Expression t)
9167 Arglist target = (Arglist) t;
9169 if (arguments != null)
9170 target.arguments = arguments.Clone (clonectx);
9173 public override object Accept (StructuralVisitor visitor)
9175 return visitor.Visit (this);
9179 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9181 FullNamedExpression texpr;
9183 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9190 public FullNamedExpression TypeExpression {
9196 public override bool ContainsEmitWithAwait ()
9201 public void AddressOf (EmitContext ec, AddressOp mode)
9204 ec.Emit (OpCodes.Refanyval, type);
9207 protected override Expression DoResolve (ResolveContext rc)
9209 expr = expr.Resolve (rc);
9210 type = texpr.ResolveAsType (rc);
9211 if (expr == null || type == null)
9214 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9215 eclass = ExprClass.Variable;
9219 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9221 return DoResolve (rc);
9224 public override void Emit (EmitContext ec)
9227 ec.Emit (OpCodes.Refanyval, type);
9228 ec.EmitLoadFromPtr (type);
9231 public void Emit (EmitContext ec, bool leave_copy)
9233 throw new NotImplementedException ();
9236 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9239 ec.Emit (OpCodes.Refanyval, type);
9242 LocalTemporary temporary = null;
9244 ec.Emit (OpCodes.Dup);
9245 temporary = new LocalTemporary (source.Type);
9246 temporary.Store (ec);
9249 ec.EmitStoreFromPtr (type);
9251 if (temporary != null) {
9252 temporary.Emit (ec);
9253 temporary.Release (ec);
9257 public override object Accept (StructuralVisitor visitor)
9259 return visitor.Visit (this);
9263 public class RefTypeExpr : ShimExpression
9265 public RefTypeExpr (Expression expr, Location loc)
9271 protected override Expression DoResolve (ResolveContext rc)
9273 expr = expr.Resolve (rc);
9277 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9281 type = rc.BuiltinTypes.Type;
9282 eclass = ExprClass.Value;
9286 public override void Emit (EmitContext ec)
9289 ec.Emit (OpCodes.Refanytype);
9290 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9292 ec.Emit (OpCodes.Call, m);
9295 public override object Accept (StructuralVisitor visitor)
9297 return visitor.Visit (this);
9301 public class MakeRefExpr : ShimExpression
9303 public MakeRefExpr (Expression expr, Location loc)
9309 public override bool ContainsEmitWithAwait ()
9311 throw new NotImplementedException ();
9314 protected override Expression DoResolve (ResolveContext rc)
9316 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9317 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9318 eclass = ExprClass.Value;
9322 public override void Emit (EmitContext ec)
9324 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9325 ec.Emit (OpCodes.Mkrefany, expr.Type);
9328 public override object Accept (StructuralVisitor visitor)
9330 return visitor.Visit (this);
9335 /// Implements the typeof operator
9337 public class TypeOf : Expression {
9338 FullNamedExpression QueriedType;
9341 public TypeOf (FullNamedExpression queried_type, Location l)
9343 QueriedType = queried_type;
9348 // Use this constructor for any compiler generated typeof expression
9350 public TypeOf (TypeSpec type, Location loc)
9352 this.typearg = type;
9358 public override bool IsSideEffectFree {
9364 public TypeSpec TypeArgument {
9370 public FullNamedExpression TypeExpression {
9379 protected override void CloneTo (CloneContext clonectx, Expression t)
9381 TypeOf target = (TypeOf) t;
9382 if (QueriedType != null)
9383 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9386 public override bool ContainsEmitWithAwait ()
9391 public override Expression CreateExpressionTree (ResolveContext ec)
9393 Arguments args = new Arguments (2);
9394 args.Add (new Argument (this));
9395 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9396 return CreateExpressionFactoryCall (ec, "Constant", args);
9399 protected override Expression DoResolve (ResolveContext ec)
9401 if (eclass != ExprClass.Unresolved)
9404 if (typearg == null) {
9406 // Pointer types are allowed without explicit unsafe, they are just tokens
9408 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9409 typearg = QueriedType.ResolveAsType (ec, true);
9412 if (typearg == null)
9415 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9416 ec.Report.Error (1962, QueriedType.Location,
9417 "The typeof operator cannot be used on the dynamic type");
9421 type = ec.BuiltinTypes.Type;
9423 // Even though what is returned is a type object, it's treated as a value by the compiler.
9424 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9425 eclass = ExprClass.Value;
9429 static bool ContainsDynamicType (TypeSpec type)
9431 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9434 var element_container = type as ElementTypeSpec;
9435 if (element_container != null)
9436 return ContainsDynamicType (element_container.Element);
9438 foreach (var t in type.TypeArguments) {
9439 if (ContainsDynamicType (t)) {
9447 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9449 // Target type is not System.Type therefore must be object
9450 // and we need to use different encoding sequence
9451 if (targetType != type)
9454 if (typearg is InflatedTypeSpec) {
9457 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9458 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9459 typearg.GetSignatureForError ());
9463 gt = gt.DeclaringType;
9464 } while (gt != null);
9467 if (ContainsDynamicType (typearg)) {
9468 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9472 enc.EncodeTypeName (typearg);
9475 public override void Emit (EmitContext ec)
9477 ec.Emit (OpCodes.Ldtoken, typearg);
9478 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9480 ec.Emit (OpCodes.Call, m);
9483 public override object Accept (StructuralVisitor visitor)
9485 return visitor.Visit (this);
9489 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9491 public TypeOfMethod (MethodSpec method, Location loc)
9492 : base (method, loc)
9496 protected override Expression DoResolve (ResolveContext ec)
9498 if (member.IsConstructor) {
9499 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9501 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9507 return base.DoResolve (ec);
9510 public override void Emit (EmitContext ec)
9512 ec.Emit (OpCodes.Ldtoken, member);
9515 ec.Emit (OpCodes.Castclass, type);
9518 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9520 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9523 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9525 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9529 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9531 protected readonly T member;
9533 protected TypeOfMember (T member, Location loc)
9535 this.member = member;
9539 public override bool IsSideEffectFree {
9545 public override bool ContainsEmitWithAwait ()
9550 public override Expression CreateExpressionTree (ResolveContext ec)
9552 Arguments args = new Arguments (2);
9553 args.Add (new Argument (this));
9554 args.Add (new Argument (new TypeOf (type, loc)));
9555 return CreateExpressionFactoryCall (ec, "Constant", args);
9558 protected override Expression DoResolve (ResolveContext ec)
9560 eclass = ExprClass.Value;
9564 public override void Emit (EmitContext ec)
9566 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9567 PredefinedMember<MethodSpec> p;
9569 p = GetTypeFromHandleGeneric (ec);
9570 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9572 p = GetTypeFromHandle (ec);
9575 var mi = p.Resolve (loc);
9577 ec.Emit (OpCodes.Call, mi);
9580 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9581 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9584 sealed class TypeOfField : TypeOfMember<FieldSpec>
9586 public TypeOfField (FieldSpec field, Location loc)
9591 protected override Expression DoResolve (ResolveContext ec)
9593 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9597 return base.DoResolve (ec);
9600 public override void Emit (EmitContext ec)
9602 ec.Emit (OpCodes.Ldtoken, member);
9606 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9608 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9611 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9613 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9618 /// Implements the sizeof expression
9620 public class SizeOf : Expression {
9621 readonly Expression texpr;
9622 TypeSpec type_queried;
9624 public SizeOf (Expression queried_type, Location l)
9626 this.texpr = queried_type;
9630 public override bool IsSideEffectFree {
9636 public Expression TypeExpression {
9642 public override bool ContainsEmitWithAwait ()
9647 public override Expression CreateExpressionTree (ResolveContext ec)
9649 Error_PointerInsideExpressionTree (ec);
9653 protected override Expression DoResolve (ResolveContext ec)
9655 type_queried = texpr.ResolveAsType (ec);
9656 if (type_queried == null)
9659 if (type_queried.IsEnum)
9660 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9662 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9664 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9667 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9672 ec.Report.Error (233, loc,
9673 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9674 type_queried.GetSignatureForError ());
9677 type = ec.BuiltinTypes.Int;
9678 eclass = ExprClass.Value;
9682 public override void Emit (EmitContext ec)
9684 ec.Emit (OpCodes.Sizeof, type_queried);
9687 protected override void CloneTo (CloneContext clonectx, Expression t)
9691 public override object Accept (StructuralVisitor visitor)
9693 return visitor.Visit (this);
9698 /// Implements the qualified-alias-member (::) expression.
9700 public class QualifiedAliasMember : MemberAccess
9702 readonly string alias;
9703 public static readonly string GlobalAlias = "global";
9705 public QualifiedAliasMember (string alias, string identifier, Location l)
9706 : base (null, identifier, l)
9711 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9712 : base (null, identifier, targs, l)
9717 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9718 : base (null, identifier, arity, l)
9723 public string Alias {
9729 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9731 if (alias == GlobalAlias)
9732 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9734 int errors = mc.Module.Compiler.Report.Errors;
9735 var expr = mc.LookupNamespaceAlias (alias);
9737 if (errors == mc.Module.Compiler.Report.Errors)
9738 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9746 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9748 expr = CreateExpressionFromAlias (mc);
9752 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9755 protected override Expression DoResolve (ResolveContext rc)
9757 return ResolveAsTypeOrNamespace (rc, false);
9760 public override string GetSignatureForError ()
9763 if (targs != null) {
9764 name = Name + "<" + targs.GetSignatureForError () + ">";
9767 return alias + "::" + name;
9770 public override bool HasConditionalAccess ()
9775 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9777 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9778 rc.Module.Compiler.Report.Error (687, loc,
9779 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9780 GetSignatureForError ());
9785 return DoResolve (rc);
9788 protected override void CloneTo (CloneContext clonectx, Expression t)
9793 public override object Accept (StructuralVisitor visitor)
9795 return visitor.Visit (this);
9800 /// Implements the member access expression
9802 public class MemberAccess : ATypeNameExpression
9804 protected Expression expr;
9806 public MemberAccess (Expression expr, string id)
9807 : base (id, expr.Location)
9812 public MemberAccess (Expression expr, string identifier, Location loc)
9813 : base (identifier, loc)
9818 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9819 : base (identifier, args, loc)
9824 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9825 : base (identifier, arity, loc)
9830 public Expression LeftExpression {
9836 public override Location StartLocation {
9838 return expr == null ? loc : expr.StartLocation;
9842 protected override Expression DoResolve (ResolveContext rc)
9844 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9846 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9851 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9853 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9855 if (e is TypeExpr) {
9856 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9861 e = e.ResolveLValue (rc, rhs);
9866 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9868 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9869 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9871 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9874 public override bool HasConditionalAccess ()
9876 return LeftExpression.HasConditionalAccess ();
9879 public static bool IsValidDotExpression (TypeSpec type)
9881 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9882 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9884 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9887 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9889 var sn = expr as SimpleName;
9890 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9893 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9896 // Resolve expression which does have type set as we need expression type
9897 // with disable flow analysis as we don't know whether left side expression
9898 // is used as variable or type
9900 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9901 expr = expr.Resolve (rc);
9902 } else if (expr is TypeParameterExpr) {
9903 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9907 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9908 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9909 expr = expr.Resolve (rc, flags);
9912 expr = expr.Resolve (rc, flags);
9919 var ns = expr as NamespaceExpression;
9921 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9923 if (retval == null) {
9924 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9929 if (HasTypeArguments)
9930 return new GenericTypeExpr (retval.Type, targs, loc);
9932 targs.Resolve (rc, false);
9938 var cma = this as ConditionalMemberAccess;
9941 TypeSpec expr_type = expr.Type;
9942 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9943 me = expr as MemberExpr;
9945 me.ResolveInstanceExpression (rc, null);
9947 Arguments args = new Arguments (1);
9948 args.Add (new Argument (expr));
9951 return new DynamicConditionalMemberBinder (Name, args, loc);
9953 return new DynamicMemberBinder (Name, args, loc);
9957 if (!IsNullPropagatingValid (expr.Type)) {
9958 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9962 if (expr_type.IsNullableType) {
9963 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9964 expr_type = expr.Type;
9968 if (!IsValidDotExpression (expr_type)) {
9969 Error_OperatorCannotBeApplied (rc, expr_type);
9973 var lookup_arity = Arity;
9974 bool errorMode = false;
9975 Expression member_lookup;
9977 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9978 if (member_lookup == null) {
9980 // Try to look for extension method when member lookup failed
9982 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9983 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9984 if (methods != null) {
9985 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9986 if (HasTypeArguments) {
9987 if (!targs.Resolve (rc, false))
9990 emg.SetTypeArguments (rc, targs);
9994 emg.ConditionalAccess = true;
9996 // TODO: it should really skip the checks bellow
9997 return emg.Resolve (rc);
10003 if (member_lookup == null) {
10004 var dep = expr_type.GetMissingDependencies ();
10006 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
10007 } else if (expr is TypeExpr) {
10008 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
10010 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
10016 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
10017 // Leave it to overload resolution to report correct error
10018 } else if (!(member_lookup is TypeExpr)) {
10019 // TODO: rc.SymbolRelatedToPreviousError
10020 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
10025 if (member_lookup != null)
10029 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
10033 TypeExpr texpr = member_lookup as TypeExpr;
10034 if (texpr != null) {
10035 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
10036 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
10037 Name, texpr.GetSignatureForError ());
10040 if (!texpr.Type.IsAccessible (rc)) {
10041 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
10042 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
10046 if (HasTypeArguments) {
10047 return new GenericTypeExpr (member_lookup.Type, targs, loc);
10050 return member_lookup;
10053 me = member_lookup as MemberExpr;
10055 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
10060 me.ConditionalAccess = true;
10063 me = me.ResolveMemberAccess (rc, expr, sn);
10066 if (!targs.Resolve (rc, false))
10069 me.SetTypeArguments (rc, targs);
10075 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
10077 FullNamedExpression fexpr = expr as FullNamedExpression;
10078 if (fexpr == null) {
10079 expr.ResolveAsType (rc);
10083 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
10085 if (expr_resolved == null)
10088 var ns = expr_resolved as NamespaceExpression;
10090 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10092 if (retval == null) {
10093 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10094 } else if (Arity > 0) {
10095 if (HasTypeArguments) {
10096 retval = new GenericTypeExpr (retval.Type, targs, loc);
10097 if (retval.ResolveAsType (rc) == null)
10100 targs.Resolve (rc, allowUnboundTypeArguments);
10102 retval = new GenericOpenTypeExpr (retval.Type, loc);
10109 var tnew_expr = expr_resolved.ResolveAsType (rc);
10110 if (tnew_expr == null)
10113 TypeSpec expr_type = tnew_expr;
10114 if (TypeManager.IsGenericParameter (expr_type)) {
10115 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10116 tnew_expr.GetSignatureForError ());
10120 var qam = this as QualifiedAliasMember;
10122 rc.Module.Compiler.Report.Error (431, loc,
10123 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10128 TypeSpec nested = null;
10129 while (expr_type != null) {
10130 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10131 if (nested == null) {
10132 if (expr_type == tnew_expr) {
10133 Error_IdentifierNotFound (rc, expr_type);
10137 expr_type = tnew_expr;
10138 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10139 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10143 if (nested.IsAccessible (rc))
10147 // Keep looking after inaccessible candidate but only if
10148 // we are not in same context as the definition itself
10150 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10153 expr_type = expr_type.BaseType;
10158 if (HasTypeArguments) {
10159 texpr = new GenericTypeExpr (nested, targs, loc);
10161 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10163 texpr = new GenericOpenTypeExpr (nested, loc);
10165 } else if (expr_resolved is GenericOpenTypeExpr) {
10166 texpr = new GenericOpenTypeExpr (nested, loc);
10168 texpr = new TypeExpression (nested, loc);
10171 if (texpr.ResolveAsType (rc) == null)
10177 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10179 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10181 if (nested != null) {
10182 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10186 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10187 if (any_other_member != null) {
10188 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10192 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10193 Name, expr_type.GetSignatureForError ());
10196 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10198 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10201 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10203 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10204 ec.Report.SymbolRelatedToPreviousError (type);
10206 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10208 // a using directive or an assembly reference
10209 if (cand != null) {
10210 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10212 missing = "an assembly reference";
10215 ec.Report.Error (1061, loc,
10216 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10217 type.GetSignatureForError (), name, missing);
10221 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10224 public override string GetSignatureForError ()
10226 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10229 protected override void CloneTo (CloneContext clonectx, Expression t)
10231 MemberAccess target = (MemberAccess) t;
10233 target.expr = expr.Clone (clonectx);
10236 public override object Accept (StructuralVisitor visitor)
10238 return visitor.Visit (this);
10242 public class ConditionalMemberAccess : MemberAccess
10244 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10245 : base (expr, identifier, args, loc)
10249 public override bool HasConditionalAccess ()
10256 /// Implements checked expressions
10258 public class CheckedExpr : Expression {
10260 public Expression Expr;
10262 public CheckedExpr (Expression e, Location l)
10268 public override bool ContainsEmitWithAwait ()
10270 return Expr.ContainsEmitWithAwait ();
10273 public override Expression CreateExpressionTree (ResolveContext ec)
10275 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10276 return Expr.CreateExpressionTree (ec);
10279 protected override Expression DoResolve (ResolveContext ec)
10281 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10282 Expr = Expr.Resolve (ec);
10287 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10290 eclass = Expr.eclass;
10295 public override void Emit (EmitContext ec)
10297 using (ec.With (EmitContext.Options.CheckedScope, true))
10301 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10303 using (ec.With (EmitContext.Options.CheckedScope, true))
10304 Expr.EmitBranchable (ec, target, on_true);
10307 public override void FlowAnalysis (FlowAnalysisContext fc)
10309 Expr.FlowAnalysis (fc);
10312 public override SLE.Expression MakeExpression (BuilderContext ctx)
10314 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10315 return Expr.MakeExpression (ctx);
10319 protected override void CloneTo (CloneContext clonectx, Expression t)
10321 CheckedExpr target = (CheckedExpr) t;
10323 target.Expr = Expr.Clone (clonectx);
10326 public override object Accept (StructuralVisitor visitor)
10328 return visitor.Visit (this);
10333 /// Implements the unchecked expression
10335 public class UnCheckedExpr : Expression {
10337 public Expression Expr;
10339 public UnCheckedExpr (Expression e, Location l)
10345 public override bool ContainsEmitWithAwait ()
10347 return Expr.ContainsEmitWithAwait ();
10350 public override Expression CreateExpressionTree (ResolveContext ec)
10352 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10353 return Expr.CreateExpressionTree (ec);
10356 protected override Expression DoResolve (ResolveContext ec)
10358 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10359 Expr = Expr.Resolve (ec);
10364 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10367 eclass = Expr.eclass;
10372 public override void Emit (EmitContext ec)
10374 using (ec.With (EmitContext.Options.CheckedScope, false))
10378 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10380 using (ec.With (EmitContext.Options.CheckedScope, false))
10381 Expr.EmitBranchable (ec, target, on_true);
10384 public override void FlowAnalysis (FlowAnalysisContext fc)
10386 Expr.FlowAnalysis (fc);
10389 protected override void CloneTo (CloneContext clonectx, Expression t)
10391 UnCheckedExpr target = (UnCheckedExpr) t;
10393 target.Expr = Expr.Clone (clonectx);
10396 public override object Accept (StructuralVisitor visitor)
10398 return visitor.Visit (this);
10403 /// An Element Access expression.
10405 /// During semantic analysis these are transformed into
10406 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10408 public class ElementAccess : Expression
10410 public Arguments Arguments;
10411 public Expression Expr;
10412 bool conditional_access_receiver;
10414 public ElementAccess (Expression e, Arguments args, Location loc)
10418 this.Arguments = args;
10421 public bool ConditionalAccess { get; set; }
10423 public override Location StartLocation {
10425 return Expr.StartLocation;
10429 public override bool ContainsEmitWithAwait ()
10431 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10435 // We perform some simple tests, and then to "split" the emit and store
10436 // code we create an instance of a different class, and return that.
10438 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10440 if (conditionalAccessReceiver)
10441 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10443 Expr = Expr.Resolve (ec);
10445 if (conditionalAccessReceiver)
10446 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10453 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10454 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10458 if (type.IsArray) {
10459 var aa = new ArrayAccess (this, loc) {
10460 ConditionalAccess = ConditionalAccess,
10463 if (conditionalAccessReceiver)
10464 aa.SetConditionalAccessReceiver ();
10469 if (type.IsPointer)
10470 return Expr.MakePointerAccess (ec, type, Arguments);
10472 FieldExpr fe = Expr as FieldExpr;
10474 var ff = fe.Spec as FixedFieldSpec;
10476 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10480 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10481 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10482 var indexer = new IndexerExpr (indexers, type, this) {
10483 ConditionalAccess = ConditionalAccess
10486 if (conditionalAccessReceiver)
10487 indexer.SetConditionalAccessReceiver ();
10492 Error_CannotApplyIndexing (ec, type, loc);
10497 public override Expression CreateExpressionTree (ResolveContext ec)
10499 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10500 Expr.CreateExpressionTree (ec));
10502 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10505 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10507 if (type != InternalType.ErrorType) {
10508 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10509 type.GetSignatureForError ());
10513 public override bool HasConditionalAccess ()
10515 return ConditionalAccess || Expr.HasConditionalAccess ();
10518 void ResolveConditionalAccessReceiver (ResolveContext rc)
10520 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10521 conditional_access_receiver = true;
10525 protected override Expression DoResolve (ResolveContext rc)
10527 ResolveConditionalAccessReceiver (rc);
10529 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10533 return expr.Resolve (rc);
10536 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10538 var res = CreateAccessExpression (ec, false);
10542 return res.ResolveLValue (ec, rhs);
10545 public override void Emit (EmitContext ec)
10547 throw new Exception ("Should never be reached");
10550 public override void FlowAnalysis (FlowAnalysisContext fc)
10552 Expr.FlowAnalysis (fc);
10554 Arguments.FlowAnalysis (fc);
10557 public override string GetSignatureForError ()
10559 return Expr.GetSignatureForError ();
10562 protected override void CloneTo (CloneContext clonectx, Expression t)
10564 ElementAccess target = (ElementAccess) t;
10566 target.Expr = Expr.Clone (clonectx);
10567 if (Arguments != null)
10568 target.Arguments = Arguments.Clone (clonectx);
10571 public override object Accept (StructuralVisitor visitor)
10573 return visitor.Visit (this);
10578 /// Implements array access
10580 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10582 // Points to our "data" repository
10586 LocalTemporary temp;
10588 bool? has_await_args;
10589 bool conditional_access_receiver;
10591 public ArrayAccess (ElementAccess ea_data, Location l)
10597 public bool ConditionalAccess { get; set; }
10599 public void AddressOf (EmitContext ec, AddressOp mode)
10601 var ac = (ArrayContainer) ea.Expr.Type;
10603 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10604 LoadInstanceAndArguments (ec, false, true);
10607 LoadInstanceAndArguments (ec, false, false);
10609 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10610 ec.Emit (OpCodes.Readonly);
10612 ec.EmitArrayAddress (ac);
10615 public override Expression CreateExpressionTree (ResolveContext ec)
10617 if (ConditionalAccess)
10618 Error_NullShortCircuitInsideExpressionTree (ec);
10620 return ea.CreateExpressionTree (ec);
10623 public override bool ContainsEmitWithAwait ()
10625 return ea.ContainsEmitWithAwait ();
10628 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10630 if (HasConditionalAccess ())
10631 Error_NullPropagatingLValue (ec);
10633 return DoResolve (ec);
10636 protected override Expression DoResolve (ResolveContext ec)
10638 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10640 ea.Arguments.Resolve (ec, out dynamic);
10642 var ac = ea.Expr.Type as ArrayContainer;
10643 int rank = ea.Arguments.Count;
10644 if (ac.Rank != rank) {
10645 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10646 rank.ToString (), ac.Rank.ToString ());
10651 if (type.IsPointer) {
10652 if (ec.CurrentIterator != null) {
10653 UnsafeInsideIteratorError (ec, ea.Location);
10654 } else if (!ec.IsUnsafe) {
10655 UnsafeError (ec, ea.Location);
10659 if (conditional_access_receiver)
10660 type = LiftMemberType (ec, type);
10662 foreach (Argument a in ea.Arguments) {
10663 var na = a as NamedArgument;
10665 ElementAccess.Error_NamedArgument (na, ec.Report);
10667 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10670 eclass = ExprClass.Variable;
10675 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10677 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10680 public override void FlowAnalysis (FlowAnalysisContext fc)
10682 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10684 ea.FlowAnalysis (fc);
10686 if (conditional_access_receiver)
10687 fc.DefiniteAssignment = da;
10690 public override bool HasConditionalAccess ()
10692 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10696 // Load the array arguments into the stack.
10698 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10700 if (prepareAwait) {
10701 ea.Expr = ea.Expr.EmitToField (ec);
10703 var ie = new InstanceEmitter (ea.Expr, false);
10704 ie.Emit (ec, ConditionalAccess);
10706 if (duplicateArguments) {
10707 ec.Emit (OpCodes.Dup);
10709 var copy = new LocalTemporary (ea.Expr.Type);
10715 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10716 if (dup_args != null)
10717 ea.Arguments = dup_args;
10720 public void Emit (EmitContext ec, bool leave_copy)
10723 ec.EmitLoadFromPtr (type);
10725 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10726 LoadInstanceAndArguments (ec, false, true);
10729 if (conditional_access_receiver)
10730 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10732 var ac = (ArrayContainer) ea.Expr.Type;
10733 LoadInstanceAndArguments (ec, false, false);
10734 ec.EmitArrayLoad (ac);
10736 if (conditional_access_receiver)
10737 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10741 ec.Emit (OpCodes.Dup);
10742 temp = new LocalTemporary (this.type);
10747 public override void Emit (EmitContext ec)
10752 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10754 var ac = (ArrayContainer) ea.Expr.Type;
10755 TypeSpec t = source.Type;
10757 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10760 // When we are dealing with a struct, get the address of it to avoid value copy
10761 // Same cannot be done for reference type because array covariance and the
10762 // check in ldelema requires to specify the type of array element stored at the index
10764 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10765 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10767 if (has_await_args.Value) {
10768 if (source.ContainsEmitWithAwait ()) {
10769 source = source.EmitToField (ec);
10770 isCompound = false;
10774 LoadInstanceAndArguments (ec, isCompound, false);
10779 ec.EmitArrayAddress (ac);
10782 ec.Emit (OpCodes.Dup);
10786 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10788 if (has_await_args.Value) {
10789 if (source.ContainsEmitWithAwait ())
10790 source = source.EmitToField (ec);
10792 LoadInstanceAndArguments (ec, false, false);
10799 var lt = ea.Expr as LocalTemporary;
10805 ec.Emit (OpCodes.Dup);
10806 temp = new LocalTemporary (this.type);
10811 ec.EmitStoreFromPtr (t);
10813 ec.EmitArrayStore (ac);
10816 if (temp != null) {
10822 public override Expression EmitToField (EmitContext ec)
10825 // Have to be specialized for arrays to get access to
10826 // underlying element. Instead of another result copy we
10827 // need direct access to element
10831 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10833 ea.Expr = ea.Expr.EmitToField (ec);
10834 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10838 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10840 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10843 public override SLE.Expression MakeExpression (BuilderContext ctx)
10845 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10848 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10850 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10851 return Arguments.MakeExpression (ea.Arguments, ctx);
10855 public void SetConditionalAccessReceiver ()
10857 conditional_access_receiver = true;
10862 // Indexer access expression
10864 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10866 IList<MemberSpec> indexers;
10867 Arguments arguments;
10868 TypeSpec queried_type;
10870 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10871 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10875 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10878 this.indexers = indexers;
10879 this.queried_type = queriedType;
10880 this.InstanceExpression = instance;
10881 this.arguments = args;
10886 protected override Arguments Arguments {
10895 protected override TypeSpec DeclaringType {
10897 return best_candidate.DeclaringType;
10901 public override bool IsInstance {
10907 public override bool IsStatic {
10913 public override string KindName {
10914 get { return "indexer"; }
10917 public override string Name {
10925 public override bool ContainsEmitWithAwait ()
10927 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10930 public override Expression CreateExpressionTree (ResolveContext ec)
10932 if (ConditionalAccess) {
10933 Error_NullShortCircuitInsideExpressionTree (ec);
10936 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10937 InstanceExpression.CreateExpressionTree (ec),
10938 new TypeOfMethod (Getter, loc));
10940 return CreateExpressionFactoryCall (ec, "Call", args);
10943 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10945 LocalTemporary await_source_arg = null;
10948 emitting_compound_assignment = true;
10949 if (source is DynamicExpressionStatement) {
10954 emitting_compound_assignment = false;
10956 if (has_await_arguments) {
10957 await_source_arg = new LocalTemporary (Type);
10958 await_source_arg.Store (ec);
10960 arguments.Add (new Argument (await_source_arg));
10963 temp = await_source_arg;
10966 has_await_arguments = false;
10971 ec.Emit (OpCodes.Dup);
10972 temp = new LocalTemporary (Type);
10978 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10979 source = source.EmitToField (ec);
10981 temp = new LocalTemporary (Type);
10988 arguments.Add (new Argument (source));
10991 var call = new CallEmitter ();
10992 call.InstanceExpression = InstanceExpression;
10993 if (arguments == null)
10994 call.InstanceExpressionOnStack = true;
10996 call.Emit (ec, Setter, arguments, loc);
10998 if (temp != null) {
11001 } else if (leave_copy) {
11005 if (await_source_arg != null) {
11006 await_source_arg.Release (ec);
11010 public override void FlowAnalysis (FlowAnalysisContext fc)
11012 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
11014 base.FlowAnalysis (fc);
11015 arguments.FlowAnalysis (fc);
11017 if (conditional_access_receiver)
11018 fc.DefiniteAssignment = da;
11021 public override string GetSignatureForError ()
11023 return best_candidate.GetSignatureForError ();
11026 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
11029 throw new NotSupportedException ();
11031 var value = new[] { source.MakeExpression (ctx) };
11032 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
11033 return SLE.Expression.Block (
11034 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
11039 public override SLE.Expression MakeExpression (BuilderContext ctx)
11042 return base.MakeExpression (ctx);
11044 var args = Arguments.MakeExpression (arguments, ctx);
11045 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
11049 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
11051 if (best_candidate != null)
11054 eclass = ExprClass.IndexerAccess;
11057 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
11058 arguments.Resolve (rc, out dynamic);
11061 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11064 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
11065 res.BaseMembersProvider = this;
11066 res.InstanceQualifier = this;
11068 // TODO: Do I need 2 argument sets?
11069 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
11070 if (best_candidate != null)
11071 type = res.BestCandidateReturnType;
11072 else if (!res.BestCandidateIsDynamic)
11077 // It has dynamic arguments
11080 Arguments args = new Arguments (arguments.Count + 1);
11082 rc.Report.Error (1972, loc,
11083 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
11085 args.Add (new Argument (InstanceExpression));
11087 args.AddRange (arguments);
11089 best_candidate = null;
11090 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11094 // Try to avoid resolving left expression again
11096 if (right_side != null)
11097 ResolveInstanceExpression (rc, right_side);
11102 protected override void CloneTo (CloneContext clonectx, Expression t)
11104 IndexerExpr target = (IndexerExpr) t;
11106 if (arguments != null)
11107 target.arguments = arguments.Clone (clonectx);
11110 public void SetConditionalAccessReceiver ()
11112 conditional_access_receiver = true;
11115 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11117 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11120 #region IBaseMembersProvider Members
11122 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11124 var baseType = type.BaseType;
11125 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11127 if (members == null && !type.IsInterface) {
11128 var tps = queried_type as TypeParameterSpec;
11130 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11136 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11138 if (queried_type == member.DeclaringType)
11141 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11142 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11145 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11154 // A base access expression
11156 public class BaseThis : This
11158 public BaseThis (Location loc)
11163 public BaseThis (TypeSpec type, Location loc)
11167 eclass = ExprClass.Variable;
11172 public override string Name {
11180 public override Expression CreateExpressionTree (ResolveContext ec)
11182 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11183 return base.CreateExpressionTree (ec);
11186 public override void Emit (EmitContext ec)
11190 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11191 var context_type = ec.CurrentType;
11192 ec.Emit (OpCodes.Ldobj, context_type);
11193 ec.Emit (OpCodes.Box, context_type);
11197 protected override void Error_ThisNotAvailable (ResolveContext ec)
11200 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11202 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11206 public override void ResolveBase (ResolveContext ec)
11208 base.ResolveBase (ec);
11209 type = ec.CurrentType.BaseType;
11212 public override object Accept (StructuralVisitor visitor)
11214 return visitor.Visit (this);
11219 /// This class exists solely to pass the Type around and to be a dummy
11220 /// that can be passed to the conversion functions (this is used by
11221 /// foreach implementation to typecast the object return value from
11222 /// get_Current into the proper type. All code has been generated and
11223 /// we only care about the side effect conversions to be performed
11225 /// This is also now used as a placeholder where a no-action expression
11226 /// is needed (the `New' class).
11228 public class EmptyExpression : Expression
11230 sealed class OutAccessExpression : EmptyExpression
11232 public OutAccessExpression (TypeSpec t)
11237 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11239 rc.Report.Error (206, right_side.Location,
11240 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11246 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11247 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11248 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11249 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11250 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11251 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11252 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11253 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11255 public EmptyExpression (TypeSpec t)
11258 eclass = ExprClass.Value;
11259 loc = Location.Null;
11262 protected override void CloneTo (CloneContext clonectx, Expression target)
11266 public override bool ContainsEmitWithAwait ()
11271 public override Expression CreateExpressionTree (ResolveContext ec)
11273 throw new NotSupportedException ("ET");
11276 protected override Expression DoResolve (ResolveContext ec)
11281 public override void Emit (EmitContext ec)
11283 // nothing, as we only exist to not do anything.
11286 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11290 public override void EmitSideEffect (EmitContext ec)
11294 public override object Accept (StructuralVisitor visitor)
11296 return visitor.Visit (this);
11300 sealed class EmptyAwaitExpression : EmptyExpression
11302 public EmptyAwaitExpression (TypeSpec type)
11307 public override bool ContainsEmitWithAwait ()
11314 // Empty statement expression
11316 public sealed class EmptyExpressionStatement : ExpressionStatement
11318 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11320 private EmptyExpressionStatement ()
11322 loc = Location.Null;
11325 public override bool ContainsEmitWithAwait ()
11330 public override Expression CreateExpressionTree (ResolveContext ec)
11335 public override void EmitStatement (EmitContext ec)
11340 protected override Expression DoResolve (ResolveContext ec)
11342 eclass = ExprClass.Value;
11343 type = ec.BuiltinTypes.Object;
11347 public override void Emit (EmitContext ec)
11352 public override object Accept (StructuralVisitor visitor)
11354 return visitor.Visit (this);
11358 public class ErrorExpression : EmptyExpression
11360 public static readonly ErrorExpression Instance = new ErrorExpression ();
11362 private ErrorExpression ()
11363 : base (InternalType.ErrorType)
11367 public override Expression CreateExpressionTree (ResolveContext ec)
11372 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11377 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11381 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11385 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11389 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11393 public override object Accept (StructuralVisitor visitor)
11395 return visitor.Visit (this);
11399 public class UserCast : Expression {
11403 public UserCast (MethodSpec method, Expression source, Location l)
11405 if (source == null)
11406 throw new ArgumentNullException ("source");
11408 this.method = method;
11409 this.source = source;
11410 type = method.ReturnType;
11414 public Expression Source {
11423 public override bool ContainsEmitWithAwait ()
11425 return source.ContainsEmitWithAwait ();
11428 public override Expression CreateExpressionTree (ResolveContext ec)
11430 Arguments args = new Arguments (3);
11431 args.Add (new Argument (source.CreateExpressionTree (ec)));
11432 args.Add (new Argument (new TypeOf (type, loc)));
11433 args.Add (new Argument (new TypeOfMethod (method, loc)));
11434 return CreateExpressionFactoryCall (ec, "Convert", args);
11437 protected override Expression DoResolve (ResolveContext ec)
11439 method.CheckObsoleteness (ec, source.Location);
11441 eclass = ExprClass.Value;
11445 public override void Emit (EmitContext ec)
11448 ec.MarkCallEntry (loc);
11449 ec.Emit (OpCodes.Call, method);
11452 public override void FlowAnalysis (FlowAnalysisContext fc)
11454 source.FlowAnalysis (fc);
11457 public override string GetSignatureForError ()
11459 return TypeManager.CSharpSignature (method);
11462 public override SLE.Expression MakeExpression (BuilderContext ctx)
11465 return base.MakeExpression (ctx);
11467 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11473 // Holds additional type specifiers like ?, *, []
11475 public class ComposedTypeSpecifier
11477 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11479 public readonly int Dimension;
11480 public readonly Location Location;
11482 public ComposedTypeSpecifier (int specifier, Location loc)
11484 this.Dimension = specifier;
11485 this.Location = loc;
11489 public bool IsNullable {
11491 return Dimension == -1;
11495 public bool IsPointer {
11497 return Dimension == -2;
11501 public ComposedTypeSpecifier Next { get; set; }
11505 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11507 return new ComposedTypeSpecifier (dimension, loc);
11510 public static ComposedTypeSpecifier CreateNullable (Location loc)
11512 return new ComposedTypeSpecifier (-1, loc);
11515 public static ComposedTypeSpecifier CreatePointer (Location loc)
11517 return new ComposedTypeSpecifier (-2, loc);
11520 public string GetSignatureForError ()
11525 ArrayContainer.GetPostfixSignature (Dimension);
11527 return Next != null ? s + Next.GetSignatureForError () : s;
11532 // This class is used to "construct" the type during a typecast
11533 // operation. Since the Type.GetType class in .NET can parse
11534 // the type specification, we just use this to construct the type
11535 // one bit at a time.
11537 public class ComposedCast : TypeExpr {
11538 FullNamedExpression left;
11539 ComposedTypeSpecifier spec;
11541 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11544 throw new ArgumentNullException ("spec");
11548 this.loc = left.Location;
11551 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11553 type = left.ResolveAsType (ec);
11557 eclass = ExprClass.Type;
11559 var single_spec = spec;
11561 if (single_spec.IsNullable) {
11562 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11566 single_spec = single_spec.Next;
11567 } else if (single_spec.IsPointer) {
11569 // Declared fields cannot have unmanaged check done before all types are defined
11571 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11574 var rc = ec as ResolveContext;
11575 if (rc?.CurrentIterator != null) {
11576 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11577 } else if (!ec.IsUnsafe) {
11578 UnsafeError (ec.Module.Compiler.Report, loc);
11582 type = PointerContainer.MakeType (ec.Module, type);
11583 single_spec = single_spec.Next;
11584 } while (single_spec != null && single_spec.IsPointer);
11587 if (single_spec != null && single_spec.Dimension > 0) {
11588 if (type.IsSpecialRuntimeType) {
11589 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11590 } else if (type.IsStatic) {
11591 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11592 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11593 type.GetSignatureForError ());
11595 MakeArray (ec.Module, single_spec);
11602 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11604 if (spec.Next != null)
11605 MakeArray (module, spec.Next);
11607 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11610 public override string GetSignatureForError ()
11612 return left.GetSignatureForError () + spec.GetSignatureForError ();
11615 public override object Accept (StructuralVisitor visitor)
11617 return visitor.Visit (this);
11621 class ReferenceTypeExpr : TypeExpr
11623 FullNamedExpression element;
11625 public ReferenceTypeExpr (FullNamedExpression element, Location loc)
11627 this.element = element;
11631 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
11633 type = element.ResolveAsType (mc);
11637 eclass = ExprClass.Type;
11638 type = ReferenceContainer.MakeType (mc.Module, type);
11643 public override string GetSignatureForError ()
11645 return "ref " + element.GetSignatureForError ();
11648 public override object Accept (StructuralVisitor visitor)
11650 return visitor.Visit (this);
11654 class FixedBufferPtr : Expression
11656 readonly Expression array;
11658 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11660 this.type = array_type;
11661 this.array = array;
11665 public override bool ContainsEmitWithAwait ()
11667 throw new NotImplementedException ();
11670 public override Expression CreateExpressionTree (ResolveContext ec)
11672 Error_PointerInsideExpressionTree (ec);
11676 public override void Emit(EmitContext ec)
11681 protected override Expression DoResolve (ResolveContext ec)
11683 type = PointerContainer.MakeType (ec.Module, type);
11684 eclass = ExprClass.Value;
11691 // This class is used to represent the address of an array, used
11692 // only by the Fixed statement, this generates "&a [0]" construct
11693 // for fixed (char *pa = a)
11695 class ArrayPtr : FixedBufferPtr
11697 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11698 base (array, array_type, l)
11702 public override void Emit (EmitContext ec)
11707 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11712 // Encapsulates a conversion rules required for array indexes
11714 public class ArrayIndexCast : TypeCast
11716 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11717 : base (expr, returnType)
11719 if (expr.Type == returnType) // int -> int
11720 throw new ArgumentException ("unnecessary array index conversion");
11723 public override Expression CreateExpressionTree (ResolveContext ec)
11725 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11726 return base.CreateExpressionTree (ec);
11730 public override void Emit (EmitContext ec)
11734 switch (child.Type.BuiltinType) {
11735 case BuiltinTypeSpec.Type.UInt:
11736 ec.Emit (OpCodes.Conv_U);
11738 case BuiltinTypeSpec.Type.Long:
11739 ec.Emit (OpCodes.Conv_Ovf_I);
11741 case BuiltinTypeSpec.Type.ULong:
11742 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11745 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11751 // Implements the `stackalloc' keyword
11753 public class StackAlloc : Expression {
11758 public StackAlloc (Expression type, Expression count, Location l)
11761 this.count = count;
11765 public Expression TypeExpression {
11771 public Expression CountExpression {
11777 public override bool ContainsEmitWithAwait ()
11782 public override Expression CreateExpressionTree (ResolveContext ec)
11784 throw new NotSupportedException ("ET");
11787 protected override Expression DoResolve (ResolveContext ec)
11789 count = count.Resolve (ec);
11793 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11794 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11799 Constant c = count as Constant;
11800 if (c != null && c.IsNegative) {
11801 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11804 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11805 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11808 otype = texpr.ResolveAsType (ec);
11812 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11815 type = PointerContainer.MakeType (ec.Module, otype);
11816 eclass = ExprClass.Value;
11821 public override void Emit (EmitContext ec)
11823 int size = BuiltinTypeSpec.GetSize (otype);
11828 ec.Emit (OpCodes.Sizeof, otype);
11832 ec.Emit (OpCodes.Mul_Ovf_Un);
11833 ec.Emit (OpCodes.Localloc);
11836 protected override void CloneTo (CloneContext clonectx, Expression t)
11838 StackAlloc target = (StackAlloc) t;
11839 target.count = count.Clone (clonectx);
11840 target.texpr = texpr.Clone (clonectx);
11843 public override object Accept (StructuralVisitor visitor)
11845 return visitor.Visit (this);
11850 // An object initializer expression
11852 public class ElementInitializer : Assign
11854 public readonly string Name;
11856 public ElementInitializer (string name, Expression initializer, Location loc)
11857 : base (null, initializer, loc)
11862 public bool IsDictionaryInitializer {
11864 return Name == null;
11868 protected override void CloneTo (CloneContext clonectx, Expression t)
11870 ElementInitializer target = (ElementInitializer) t;
11871 target.source = source.Clone (clonectx);
11874 public override Expression CreateExpressionTree (ResolveContext ec)
11876 Arguments args = new Arguments (2);
11877 FieldExpr fe = target as FieldExpr;
11879 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11881 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11884 Expression arg_expr;
11885 var cinit = source as CollectionOrObjectInitializers;
11886 if (cinit == null) {
11888 arg_expr = source.CreateExpressionTree (ec);
11890 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11891 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11894 args.Add (new Argument (arg_expr));
11895 return CreateExpressionFactoryCall (ec, mname, args);
11898 protected override Expression DoResolve (ResolveContext ec)
11900 if (source == null)
11901 return EmptyExpressionStatement.Instance;
11903 if (!ResolveElement (ec))
11906 if (source is CollectionOrObjectInitializers) {
11907 target = target.Resolve (ec);
11908 if (target == null)
11911 Expression previous = ec.CurrentInitializerVariable;
11912 ec.CurrentInitializerVariable = target;
11913 source = source.Resolve (ec);
11914 ec.CurrentInitializerVariable = previous;
11915 if (source == null)
11918 eclass = source.eclass;
11919 type = source.Type;
11924 return base.DoResolve (ec);
11927 public override void EmitStatement (EmitContext ec)
11929 if (source is CollectionOrObjectInitializers)
11932 base.EmitStatement (ec);
11935 protected virtual bool ResolveElement (ResolveContext rc)
11937 var t = rc.CurrentInitializerVariable.Type;
11938 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11939 Arguments args = new Arguments (1);
11940 args.Add (new Argument (rc.CurrentInitializerVariable));
11941 target = new DynamicMemberBinder (Name, args, loc);
11943 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11944 if (member == null) {
11945 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11947 if (member != null) {
11948 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11949 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11954 if (member == null) {
11955 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11959 var me = member as MemberExpr;
11960 if (me is EventExpr) {
11961 me = me.ResolveMemberAccess (rc, null, null);
11962 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11963 rc.Report.Error (1913, loc,
11964 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11965 member.GetSignatureForError ());
11971 rc.Report.Error (1914, loc,
11972 "Static field or property `{0}' cannot be assigned in an object initializer",
11973 me.GetSignatureForError ());
11977 me.InstanceExpression = rc.CurrentInitializerVariable;
11985 // A collection initializer expression
11987 class CollectionElementInitializer : Invocation
11989 public class ElementInitializerArgument : Argument
11991 public ElementInitializerArgument (Expression e)
11997 sealed class AddMemberAccess : MemberAccess
11999 public AddMemberAccess (Expression expr, Location loc)
12000 : base (expr, "Add", loc)
12004 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
12006 if (TypeManager.HasElementType (type))
12009 base.Error_TypeDoesNotContainDefinition (ec, type, name);
12013 public CollectionElementInitializer (Expression argument)
12014 : base (null, new Arguments (1))
12016 base.arguments.Add (new ElementInitializerArgument (argument));
12017 this.loc = argument.Location;
12020 public CollectionElementInitializer (List<Expression> arguments, Location loc)
12021 : base (null, new Arguments (arguments.Count))
12023 foreach (Expression e in arguments)
12024 base.arguments.Add (new ElementInitializerArgument (e));
12029 public CollectionElementInitializer (Location loc)
12030 : base (null, null)
12035 public override Expression CreateExpressionTree (ResolveContext ec)
12037 Arguments args = new Arguments (2);
12038 args.Add (new Argument (mg.CreateExpressionTree (ec)));
12040 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
12041 foreach (Argument a in arguments) {
12042 if (a.ArgType == Argument.AType.ExtensionType) {
12043 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
12046 expr_initializers.Add (a.CreateExpressionTree (ec));
12049 args.Add (new Argument (new ArrayCreation (
12050 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
12051 return CreateExpressionFactoryCall (ec, "ElementInit", args);
12054 protected override void CloneTo (CloneContext clonectx, Expression t)
12056 CollectionElementInitializer target = (CollectionElementInitializer) t;
12057 if (arguments != null)
12058 target.arguments = arguments.Clone (clonectx);
12061 protected override Expression DoResolve (ResolveContext ec)
12063 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
12065 return base.DoResolve (ec);
12069 class DictionaryElementInitializer : ElementInitializer
12071 readonly Arguments args;
12073 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
12074 : base (null, initializer, loc)
12076 this.args = arguments;
12079 public override Expression CreateExpressionTree (ResolveContext ec)
12081 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
12085 protected override bool ResolveElement (ResolveContext rc)
12087 var init = rc.CurrentInitializerVariable;
12088 var type = init.Type;
12090 if (type.IsArray) {
12091 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
12095 if (type.IsPointer) {
12096 target = init.MakePointerAccess (rc, type, args);
12100 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
12101 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12102 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
12106 target = new IndexerExpr (indexers, type, init, args, loc);
12112 // A block of object or collection initializers
12114 public class CollectionOrObjectInitializers : ExpressionStatement
12116 IList<Expression> initializers;
12117 bool is_collection_initialization;
12119 public CollectionOrObjectInitializers (Location loc)
12120 : this (new Expression[0], loc)
12124 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12126 this.initializers = initializers;
12130 public IList<Expression> Initializers {
12132 return initializers;
12136 public bool IsEmpty {
12138 return initializers.Count == 0;
12142 public bool IsCollectionInitializer {
12144 return is_collection_initialization;
12148 protected override void CloneTo (CloneContext clonectx, Expression target)
12150 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12152 t.initializers = new List<Expression> (initializers.Count);
12153 foreach (var e in initializers)
12154 t.initializers.Add (e.Clone (clonectx));
12157 public override bool ContainsEmitWithAwait ()
12159 foreach (var e in initializers) {
12160 if (e.ContainsEmitWithAwait ())
12167 public override Expression CreateExpressionTree (ResolveContext ec)
12169 return CreateExpressionTree (ec, false);
12172 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12174 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12175 foreach (Expression e in initializers) {
12176 Expression expr = e.CreateExpressionTree (ec);
12178 expr_initializers.Add (expr);
12182 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12184 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12187 protected override Expression DoResolve (ResolveContext ec)
12189 List<string> element_names = null;
12190 for (int i = 0; i < initializers.Count; ++i) {
12191 Expression initializer = initializers [i];
12192 ElementInitializer element_initializer = initializer as ElementInitializer;
12195 if (element_initializer != null) {
12196 element_names = new List<string> (initializers.Count);
12197 if (!element_initializer.IsDictionaryInitializer)
12198 element_names.Add (element_initializer.Name);
12199 } else if (initializer is CompletingExpression) {
12200 initializer.Resolve (ec);
12201 throw new InternalErrorException ("This line should never be reached");
12203 var t = ec.CurrentInitializerVariable.Type;
12204 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12205 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12206 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12207 "object initializer because type `{1}' does not implement `{2}' interface",
12208 ec.CurrentInitializerVariable.GetSignatureForError (),
12209 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12210 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12213 is_collection_initialization = true;
12216 if (is_collection_initialization != (element_initializer == null)) {
12217 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12218 is_collection_initialization ? "collection initializer" : "object initializer");
12222 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12223 if (element_names.Contains (element_initializer.Name)) {
12224 ec.Report.Error (1912, element_initializer.Location,
12225 "An object initializer includes more than one member `{0}' initialization",
12226 element_initializer.Name);
12228 element_names.Add (element_initializer.Name);
12233 Expression e = initializer.Resolve (ec);
12234 if (e == EmptyExpressionStatement.Instance)
12235 initializers.RemoveAt (i--);
12237 initializers [i] = e;
12240 type = ec.CurrentInitializerVariable.Type;
12241 if (is_collection_initialization) {
12242 if (TypeManager.HasElementType (type)) {
12243 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12244 type.GetSignatureForError ());
12248 eclass = ExprClass.Variable;
12252 public override void Emit (EmitContext ec)
12254 EmitStatement (ec);
12257 public override void EmitStatement (EmitContext ec)
12259 foreach (ExpressionStatement e in initializers) {
12260 // TODO: need location region
12261 ec.Mark (e.Location);
12262 e.EmitStatement (ec);
12266 public override void FlowAnalysis (FlowAnalysisContext fc)
12268 foreach (var initializer in initializers) {
12269 if (initializer != null)
12270 initializer.FlowAnalysis (fc);
12276 // New expression with element/object initializers
12278 public class NewInitialize : New
12281 // This class serves as a proxy for variable initializer target instances.
12282 // A real variable is assigned later when we resolve left side of an
12285 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12287 NewInitialize new_instance;
12289 public InitializerTargetExpression (NewInitialize newInstance)
12291 this.type = newInstance.type;
12292 this.loc = newInstance.loc;
12293 this.eclass = newInstance.eclass;
12294 this.new_instance = newInstance;
12297 public override bool ContainsEmitWithAwait ()
12302 public override Expression CreateExpressionTree (ResolveContext ec)
12304 // Should not be reached
12305 throw new NotSupportedException ("ET");
12308 protected override Expression DoResolve (ResolveContext ec)
12313 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12318 public override void Emit (EmitContext ec)
12320 Expression e = (Expression) new_instance.instance;
12324 public override Expression EmitToField (EmitContext ec)
12326 return (Expression) new_instance.instance;
12329 #region IMemoryLocation Members
12331 public void AddressOf (EmitContext ec, AddressOp mode)
12333 new_instance.instance.AddressOf (ec, mode);
12339 CollectionOrObjectInitializers initializers;
12340 IMemoryLocation instance;
12341 DynamicExpressionStatement dynamic;
12343 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12344 : base (requested_type, arguments, l)
12346 this.initializers = initializers;
12349 public CollectionOrObjectInitializers Initializers {
12351 return initializers;
12355 protected override void CloneTo (CloneContext clonectx, Expression t)
12357 base.CloneTo (clonectx, t);
12359 NewInitialize target = (NewInitialize) t;
12360 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12363 public override bool ContainsEmitWithAwait ()
12365 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12368 public override Expression CreateExpressionTree (ResolveContext ec)
12370 Arguments args = new Arguments (2);
12371 args.Add (new Argument (base.CreateExpressionTree (ec)));
12372 if (!initializers.IsEmpty)
12373 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12375 return CreateExpressionFactoryCall (ec,
12376 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12380 protected override Expression DoResolve (ResolveContext rc)
12382 Expression e = base.DoResolve (rc);
12386 if (type.IsDelegate) {
12387 rc.Report.Error (1958, Initializers.Location,
12388 "Object and collection initializers cannot be used to instantiate a delegate");
12391 Expression previous = rc.CurrentInitializerVariable;
12392 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12393 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12394 initializers.Resolve (rc);
12396 rc.CurrentInitializerVariable = previous;
12398 dynamic = e as DynamicExpressionStatement;
12399 if (dynamic != null)
12405 public override void Emit (EmitContext ec)
12407 if (!CanEmitOptimizedLocalTarget (ec)) {
12408 var fe = ec.GetTemporaryField (type);
12410 if (!Emit (ec, fe))
12419 public override bool Emit (EmitContext ec, IMemoryLocation target)
12422 // Expression is initialized into temporary target then moved
12423 // to real one for atomicity
12425 IMemoryLocation temp_target = target;
12427 LocalTemporary temp = null;
12428 bool by_ref = false;
12429 if (!initializers.IsEmpty) {
12430 temp_target = target as LocalTemporary;
12431 if (temp_target == null)
12432 temp_target = target as StackFieldExpr;
12434 if (temp_target == null) {
12435 var vr = target as VariableReference;
12436 if (vr != null && vr.IsRef) {
12442 if (temp_target == null)
12443 temp_target = temp = new LocalTemporary (type);
12446 bool left_on_stack;
12447 if (dynamic != null) {
12449 left_on_stack = true;
12451 left_on_stack = base.Emit (ec, temp_target);
12454 if (initializers.IsEmpty)
12455 return left_on_stack;
12457 StackFieldExpr sf = null;
12459 // Move a new instance (reference-type) to local temporary variable
12460 if (left_on_stack) {
12462 temp_target = temp = new LocalTemporary (type);
12468 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12470 throw new NotImplementedException ();
12472 sf = ec.GetTemporaryField (type);
12473 sf.AutomaticallyReuse = false;
12474 sf.EmitAssign (ec, temp, false, false);
12477 left_on_stack = false;
12481 instance = temp_target;
12483 initializers.Emit (ec);
12485 ((Expression)temp_target).Emit (ec);
12491 sf.PrepareCleanup (ec);
12496 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12498 return !(method == null && TypeSpec.IsValueType (type) &&
12499 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12500 initializers.ContainsEmitWithAwait ());
12503 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12505 instance = base.EmitAddressOf (ec, Mode);
12507 if (!initializers.IsEmpty)
12508 initializers.Emit (ec);
12513 public override void FlowAnalysis (FlowAnalysisContext fc)
12515 base.FlowAnalysis (fc);
12516 initializers.FlowAnalysis (fc);
12519 public override object Accept (StructuralVisitor visitor)
12521 return visitor.Visit (this);
12525 public class NewAnonymousType : New
12527 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12529 List<AnonymousTypeParameter> parameters;
12530 readonly TypeContainer parent;
12531 AnonymousTypeClass anonymous_type;
12533 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12534 : base (null, null, loc)
12536 this.parameters = parameters;
12537 this.parent = parent;
12540 public List<AnonymousTypeParameter> Parameters {
12542 return this.parameters;
12546 protected override void CloneTo (CloneContext clonectx, Expression target)
12548 if (parameters == null)
12551 NewAnonymousType t = (NewAnonymousType) target;
12552 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12553 foreach (AnonymousTypeParameter atp in parameters)
12554 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12557 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12559 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12563 type = AnonymousTypeClass.Create (parent, parameters, loc);
12567 int errors = ec.Report.Errors;
12568 type.CreateContainer ();
12569 type.DefineContainer ();
12570 type.ExpandBaseInterfaces ();
12572 if ((ec.Report.Errors - errors) == 0) {
12573 parent.Module.AddAnonymousType (type);
12574 type.PrepareEmit ();
12580 public override Expression CreateExpressionTree (ResolveContext ec)
12582 if (parameters == null)
12583 return base.CreateExpressionTree (ec);
12585 var init = new ArrayInitializer (parameters.Count, loc);
12586 foreach (var m in anonymous_type.Members) {
12587 var p = m as Property;
12589 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12592 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12593 foreach (Argument a in arguments)
12594 ctor_args.Add (a.CreateExpressionTree (ec));
12596 Arguments args = new Arguments (3);
12597 args.Add (new Argument (new TypeOfMethod (method, loc)));
12598 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12599 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12601 return CreateExpressionFactoryCall (ec, "New", args);
12604 protected override Expression DoResolve (ResolveContext ec)
12606 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12607 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12611 if (parameters == null) {
12612 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12613 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12614 return base.DoResolve (ec);
12617 bool error = false;
12618 arguments = new Arguments (parameters.Count);
12619 var t_args = new TypeSpec [parameters.Count];
12620 for (int i = 0; i < parameters.Count; ++i) {
12621 Expression e = parameters [i].Resolve (ec);
12627 arguments.Add (new Argument (e));
12628 t_args [i] = e.Type;
12634 anonymous_type = CreateAnonymousType (ec, parameters);
12635 if (anonymous_type == null)
12638 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12639 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12640 eclass = ExprClass.Value;
12644 public override object Accept (StructuralVisitor visitor)
12646 return visitor.Visit (this);
12650 public class AnonymousTypeParameter : ShimExpression
12652 public readonly string Name;
12654 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12655 : base (initializer)
12661 public AnonymousTypeParameter (Parameter parameter)
12662 : base (new SimpleName (parameter.Name, parameter.Location))
12664 this.Name = parameter.Name;
12665 this.loc = parameter.Location;
12668 public override bool Equals (object o)
12670 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12671 return other != null && Name == other.Name;
12674 public override int GetHashCode ()
12676 return Name.GetHashCode ();
12679 protected override Expression DoResolve (ResolveContext ec)
12681 Expression e = expr.Resolve (ec);
12685 if (e.eclass == ExprClass.MethodGroup) {
12686 Error_InvalidInitializer (ec, e.ExprClassName);
12691 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
12692 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12699 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12701 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12702 Name, initializer);
12706 public class CatchFilterExpression : BooleanExpression
12708 public CatchFilterExpression (Expression expr, Location loc)
12715 public class InterpolatedString : Expression
12717 readonly StringLiteral start, end;
12718 List<Expression> interpolations;
12719 Arguments arguments;
12721 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12723 this.start = start;
12725 this.interpolations = interpolations;
12726 loc = start.Location;
12729 protected override void CloneTo (CloneContext clonectx, Expression t)
12731 InterpolatedString target = (InterpolatedString) t;
12733 if (interpolations != null) {
12734 target.interpolations = new List<Expression> ();
12735 foreach (var interpolation in interpolations) {
12736 target.interpolations.Add (interpolation.Clone (clonectx));
12741 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12743 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12744 if (factory == null)
12747 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12748 var res = new Invocation (ma, arguments).Resolve (rc);
12749 if (res != null && res.Type != type)
12750 res = Convert.ExplicitConversion (rc, res, type, loc);
12755 public override bool ContainsEmitWithAwait ()
12757 if (interpolations == null)
12760 foreach (var expr in interpolations) {
12761 if (expr.ContainsEmitWithAwait ())
12768 public override Expression CreateExpressionTree (ResolveContext rc)
12770 var best = ResolveBestFormatOverload (rc);
12774 Expression instance = new NullLiteral (loc);
12775 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12776 return CreateExpressionFactoryCall (rc, "Call", args);
12779 protected override Expression DoResolve (ResolveContext rc)
12783 if (interpolations == null) {
12785 arguments = new Arguments (1);
12787 arguments = new Arguments (interpolations.Count);
12789 var sb = new StringBuilder (start.Value);
12790 for (int i = 0; i < interpolations.Count; ++i) {
12792 sb.Append ('{').Append (i / 2);
12793 var isi = (InterpolatedStringInsert)interpolations [i];
12794 if (isi.Alignment != null) {
12796 var value = isi.ResolveAligment (rc);
12798 sb.Append (value.Value);
12801 if (isi.Format != null) {
12803 sb.Append (isi.Format);
12807 arguments.Add (new Argument (isi.Resolve (rc)));
12809 sb.Append (((StringLiteral)interpolations [i]).Value);
12813 sb.Append (end.Value);
12814 str = sb.ToString ();
12817 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12819 eclass = ExprClass.Value;
12820 type = rc.BuiltinTypes.String;
12824 public override void Emit (EmitContext ec)
12826 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12827 if (interpolations == null) {
12828 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12829 if (str != start.Value)
12830 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12837 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12841 var ca = new CallEmitter ();
12842 ca.Emit (ec, best, arguments, loc);
12845 public override void FlowAnalysis (FlowAnalysisContext fc)
12847 if (interpolations != null) {
12848 foreach (var expr in interpolations) {
12849 expr.FlowAnalysis (fc);
12854 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12856 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12857 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12858 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12862 public class InterpolatedStringInsert : CompositeExpression
12864 public InterpolatedStringInsert (Expression expr)
12869 public Expression Alignment { get; set; }
12870 public string Format { get; set; }
12872 protected override void CloneTo (CloneContext clonectx, Expression t)
12874 var target = (InterpolatedStringInsert)t;
12875 target.expr = expr.Clone (clonectx);
12876 if (Alignment != null)
12877 target.Alignment = Alignment.Clone (clonectx);
12880 protected override Expression DoResolve (ResolveContext rc)
12882 var expr = base.DoResolve (rc);
12887 // For better error reporting, assumes the built-in implementation uses object
12890 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12893 public override void FlowAnalysis (FlowAnalysisContext fc)
12895 Child.FlowAnalysis (fc);
12898 public int? ResolveAligment (ResolveContext rc)
12900 var c = Alignment.ResolveLabelConstant (rc);
12904 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12908 var value = (int) c.GetValueAsLong ();
12909 if (value > 32767 || value < -32767) {
12910 rc.Report.Warning (8094, 1, Alignment.Location,
12911 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12918 class ThrowExpression : ExpressionStatement
12922 public ThrowExpression (Expression expr, Location loc)
12928 protected override void CloneTo (CloneContext clonectx, Expression t)
12930 var target = (ThrowExpression)t;
12931 target.expr = expr.Clone (clonectx);
12934 public override bool ContainsEmitWithAwait ()
12936 return expr.ContainsEmitWithAwait ();
12939 public override Expression CreateExpressionTree (ResolveContext rc)
12941 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12945 protected override Expression DoResolve (ResolveContext rc)
12947 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12952 expr = Throw.ConvertType (rc, expr);
12954 eclass = ExprClass.Value;
12955 type = InternalType.ThrowExpr;
12959 public override void Emit (EmitContext ec)
12961 EmitStatement (ec);
12964 public override void EmitStatement (EmitContext ec)
12968 ec.Emit (OpCodes.Throw);
12971 public override void FlowAnalysis (FlowAnalysisContext fc)
12973 expr.FlowAnalysis (fc);
12976 public override Reachability MarkReachable (Reachability rc)
12978 return Reachability.CreateUnreachable ();
12982 class ReferenceExpression : CompositeExpression
12984 public ReferenceExpression (Expression expr, Location loc)
12990 static bool CanBeByRef (Expression expr)
12992 if (expr is IAssignMethod)
12995 var invocation = expr as Invocation;
12996 if (invocation?.Type.Kind == MemberKind.ByRef)
13002 public override Expression CreateExpressionTree (ResolveContext rc)
13004 throw new NotSupportedException ("ET");
13007 protected override Expression DoResolve (ResolveContext rc)
13009 var res = expr.DoResolveLValue (rc, EmptyExpression.OutAccess);
13010 if (res == null || !CanBeByRef (res)) {
13011 if (res?.Type != InternalType.ErrorType)
13012 rc.Report.Error (8156, expr.Location, "An expression cannot be used in this context because it may not be returned by reference");
13013 return ErrorExpression.Instance;
13017 var type_container = type as ReferenceContainer;
13018 if (type_container != null)
13019 type = type_container.Element;
13022 eclass = ExprClass.Value;
13026 public override void Emit (EmitContext ec)
13028 var ml = expr as IMemoryLocation;
13030 ml.AddressOf (ec, AddressOp.LoadStore);
13035 public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl)
13037 rc.Report.Error (8173, loc, "The expression must be of type `{0}' because it is being assigned by reference", target.GetSignatureForError ());
13041 class ByRefDereference : CompositeExpression, IMemoryLocation, IAssignMethod
13044 LocalTemporary temporary;
13046 private ByRefDereference (Expression expr)
13051 public static Expression Create (Expression expr)
13053 var rc = expr.Type as ReferenceContainer;
13057 return new ByRefDereference (expr) {
13062 public void AddressOf (EmitContext ec, AddressOp mode)
13067 public void Emit (EmitContext ec, bool leave_copy)
13071 ec.Emit (OpCodes.Dup);
13072 temporary = new LocalTemporary (type);
13073 temporary.Store (ec);
13077 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
13079 prepared = isCompound;
13084 ec.Emit (OpCodes.Dup);
13088 throw new NotImplementedException ("leave_copy");
13091 ec.EmitStoreFromPtr (type);
13093 if (temporary != null) {
13094 temporary.Emit (ec);
13095 temporary.Release (ec);
13099 protected override Expression DoResolve (ResolveContext rc)
13101 eclass = ExprClass.Variable;
13105 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
13107 return DoResolve (rc);
13110 public override void Emit (EmitContext ec)
13115 ec.EmitLoadFromPtr (type);
13118 public override object Accept (StructuralVisitor visitor)
13120 return visitor.Visit (this);