2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
721 if (ec.CurrentIterator != null) {
722 UnsafeInsideIteratorError (ec, loc);
723 } else if (!ec.IsUnsafe) {
724 UnsafeError (ec, loc);
727 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
728 if (Expr == null || Expr.eclass != ExprClass.Variable) {
729 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
733 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
737 IVariableReference vr = Expr as IVariableReference;
740 is_fixed = vr.IsFixed;
741 vr.SetHasAddressTaken ();
743 if (vr.IsHoisted && ec.CurrentIterator == null) {
744 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
747 IFixedExpression fe = Expr as IFixedExpression;
748 is_fixed = fe != null && fe.IsFixed;
751 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
752 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
755 type = PointerContainer.MakeType (ec.Module, Expr.Type);
756 eclass = ExprClass.Value;
760 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
762 expr = DoNumericPromotion (rc, Oper, expr);
763 TypeSpec expr_type = expr.Type;
764 foreach (TypeSpec t in predefined) {
772 // Perform user-operator overload resolution
774 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
776 CSharp.Operator.OpType op_type;
778 case Operator.LogicalNot:
779 op_type = CSharp.Operator.OpType.LogicalNot; break;
780 case Operator.OnesComplement:
781 op_type = CSharp.Operator.OpType.OnesComplement; break;
782 case Operator.UnaryNegation:
783 op_type = CSharp.Operator.OpType.UnaryNegation; break;
784 case Operator.UnaryPlus:
785 op_type = CSharp.Operator.OpType.UnaryPlus; break;
787 throw new InternalErrorException (Oper.ToString ());
790 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
794 Arguments args = new Arguments (1);
795 args.Add (new Argument (expr));
797 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
798 var oper = res.ResolveOperator (ec, ref args);
803 Expr = args [0].Expr;
804 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
808 // Unary user type overload resolution
810 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
812 Expression best_expr = ResolveUserOperator (ec, expr);
813 if (best_expr != null)
816 foreach (TypeSpec t in predefined) {
817 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
818 if (oper_expr == null)
821 if (oper_expr == ErrorExpression.Instance)
825 // decimal type is predefined but has user-operators
827 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
828 oper_expr = ResolveUserType (ec, oper_expr, predefined);
830 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
832 if (oper_expr == null)
835 if (best_expr == null) {
836 best_expr = oper_expr;
840 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
842 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
843 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
845 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
852 best_expr = oper_expr;
855 if (best_expr == null)
859 // HACK: Decimal user-operator is included in standard operators
861 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
865 type = best_expr.Type;
869 protected override void CloneTo (CloneContext clonectx, Expression t)
871 Unary target = (Unary) t;
873 target.Expr = Expr.Clone (clonectx);
876 public override object Accept (StructuralVisitor visitor)
878 return visitor.Visit (this);
884 // Unary operators are turned into Indirection expressions
885 // after semantic analysis (this is so we can take the address
886 // of an indirection).
888 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
890 LocalTemporary temporary;
893 public Indirection (Expression expr, Location l)
899 public Expression Expr {
905 public bool IsFixed {
909 public override Location StartLocation {
911 return expr.StartLocation;
915 protected override void CloneTo (CloneContext clonectx, Expression t)
917 Indirection target = (Indirection) t;
918 target.expr = expr.Clone (clonectx);
921 public override bool ContainsEmitWithAwait ()
923 throw new NotImplementedException ();
926 public override Expression CreateExpressionTree (ResolveContext ec)
928 Error_PointerInsideExpressionTree (ec);
932 public override void Emit (EmitContext ec)
937 ec.EmitLoadFromPtr (Type);
940 public void Emit (EmitContext ec, bool leave_copy)
944 ec.Emit (OpCodes.Dup);
945 temporary = new LocalTemporary (expr.Type);
946 temporary.Store (ec);
950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
952 prepared = isCompound;
957 ec.Emit (OpCodes.Dup);
961 ec.Emit (OpCodes.Dup);
962 temporary = new LocalTemporary (source.Type);
963 temporary.Store (ec);
966 ec.EmitStoreFromPtr (type);
968 if (temporary != null) {
970 temporary.Release (ec);
974 public void AddressOf (EmitContext ec, AddressOp Mode)
979 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
981 return DoResolve (ec);
984 protected override Expression DoResolve (ResolveContext ec)
986 expr = expr.Resolve (ec);
990 if (ec.CurrentIterator != null) {
991 UnsafeInsideIteratorError (ec, loc);
992 } else if (!ec.IsUnsafe) {
993 UnsafeError (ec, loc);
996 var pc = expr.Type as PointerContainer;
999 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1005 if (type.Kind == MemberKind.Void) {
1006 Error_VoidPointerOperation (ec);
1010 eclass = ExprClass.Variable;
1014 public override object Accept (StructuralVisitor visitor)
1016 return visitor.Visit (this);
1021 /// Unary Mutator expressions (pre and post ++ and --)
1025 /// UnaryMutator implements ++ and -- expressions. It derives from
1026 /// ExpressionStatement becuase the pre/post increment/decrement
1027 /// operators can be used in a statement context.
1029 /// FIXME: Idea, we could split this up in two classes, one simpler
1030 /// for the common case, and one with the extra fields for more complex
1031 /// classes (indexers require temporary access; overloaded require method)
1034 public class UnaryMutator : ExpressionStatement
1036 class DynamicPostMutator : Expression, IAssignMethod
1038 LocalTemporary temp;
1041 public DynamicPostMutator (Expression expr)
1044 this.type = expr.Type;
1045 this.loc = expr.Location;
1048 public override Expression CreateExpressionTree (ResolveContext ec)
1050 throw new NotImplementedException ("ET");
1053 protected override Expression DoResolve (ResolveContext rc)
1055 eclass = expr.eclass;
1059 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1061 expr.DoResolveLValue (ec, right_side);
1062 return DoResolve (ec);
1065 public override void Emit (EmitContext ec)
1070 public void Emit (EmitContext ec, bool leave_copy)
1072 throw new NotImplementedException ();
1076 // Emits target assignment using unmodified source value
1078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1081 // Allocate temporary variable to keep original value before it's modified
1083 temp = new LocalTemporary (type);
1087 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1098 public enum Mode : byte {
1105 PreDecrement = IsDecrement,
1106 PostIncrement = IsPost,
1107 PostDecrement = IsPost | IsDecrement
1111 bool is_expr, recurse;
1113 protected Expression expr;
1115 // Holds the real operation
1116 Expression operation;
1118 public UnaryMutator (Mode m, Expression e, Location loc)
1125 public Mode UnaryMutatorMode {
1131 public Expression Expr {
1137 public override Location StartLocation {
1139 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1143 public override bool ContainsEmitWithAwait ()
1145 return expr.ContainsEmitWithAwait ();
1148 public override Expression CreateExpressionTree (ResolveContext ec)
1150 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1153 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1156 // Predefined ++ and -- operators exist for the following types:
1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1159 return new TypeSpec[] {
1175 protected override Expression DoResolve (ResolveContext ec)
1177 expr = expr.Resolve (ec);
1179 if (expr == null || expr.Type == InternalType.ErrorType)
1182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 // Handle postfix unary operators using local
1185 // temporary variable
1187 if ((mode & Mode.IsPost) != 0)
1188 expr = new DynamicPostMutator (expr);
1190 Arguments args = new Arguments (1);
1191 args.Add (new Argument (expr));
1192 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1195 if (expr.Type.IsNullableType)
1196 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1198 return DoResolveOperation (ec);
1201 protected Expression DoResolveOperation (ResolveContext ec)
1203 eclass = ExprClass.Value;
1206 if (expr is RuntimeValueExpression) {
1209 // Use itself at the top of the stack
1210 operation = new EmptyExpression (type);
1214 // The operand of the prefix/postfix increment decrement operators
1215 // should be an expression that is classified as a variable,
1216 // a property access or an indexer access
1218 // TODO: Move to parser, expr is ATypeNameExpression
1219 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1220 expr = expr.ResolveLValue (ec, expr);
1222 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1226 // Step 1: Try to find a user operator, it has priority over predefined ones
1228 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1229 var methods = MemberCache.GetUserOperator (type, user_op, false);
1231 if (methods != null) {
1232 Arguments args = new Arguments (1);
1233 args.Add (new Argument (expr));
1235 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1236 var method = res.ResolveOperator (ec, ref args);
1240 args[0].Expr = operation;
1241 operation = new UserOperatorCall (method, args, null, loc);
1242 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1247 // Step 2: Try predefined types
1250 Expression source = null;
1251 bool primitive_type;
1254 // Predefined without user conversion first for speed-up
1256 // Predefined ++ and -- operators exist for the following types:
1257 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1259 switch (type.BuiltinType) {
1260 case BuiltinTypeSpec.Type.Byte:
1261 case BuiltinTypeSpec.Type.SByte:
1262 case BuiltinTypeSpec.Type.Short:
1263 case BuiltinTypeSpec.Type.UShort:
1264 case BuiltinTypeSpec.Type.Int:
1265 case BuiltinTypeSpec.Type.UInt:
1266 case BuiltinTypeSpec.Type.Long:
1267 case BuiltinTypeSpec.Type.ULong:
1268 case BuiltinTypeSpec.Type.Char:
1269 case BuiltinTypeSpec.Type.Float:
1270 case BuiltinTypeSpec.Type.Double:
1271 case BuiltinTypeSpec.Type.Decimal:
1273 primitive_type = true;
1276 primitive_type = false;
1278 // ++/-- on pointer variables of all types except void*
1279 if (type.IsPointer) {
1280 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1281 Error_VoidPointerOperation (ec);
1287 Expression best_source = null;
1288 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1289 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1291 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1295 if (best_source == null) {
1296 best_source = source;
1300 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1305 best_source = source;
1309 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1313 source = best_source;
1316 // ++/-- on enum types
1317 if (source == null && type.IsEnum)
1320 if (source == null) {
1321 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1328 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1329 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1330 operation = new Binary (op, source, one);
1331 operation = operation.Resolve (ec);
1332 if (operation == null)
1333 throw new NotImplementedException ("should not be reached");
1335 if (operation.Type != type) {
1337 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1339 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1345 void EmitCode (EmitContext ec, bool is_expr)
1348 this.is_expr = is_expr;
1349 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1352 public override void Emit (EmitContext ec)
1355 // We use recurse to allow ourselfs to be the source
1356 // of an assignment. This little hack prevents us from
1357 // having to allocate another expression
1360 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1368 EmitCode (ec, true);
1371 protected virtual void EmitOperation (EmitContext ec)
1373 operation.Emit (ec);
1376 public override void EmitStatement (EmitContext ec)
1378 EmitCode (ec, false);
1381 public override void FlowAnalysis (FlowAnalysisContext fc)
1383 expr.FlowAnalysis (fc);
1387 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1389 string GetOperatorExpressionTypeName ()
1391 return IsDecrement ? "Decrement" : "Increment";
1395 get { return (mode & Mode.IsDecrement) != 0; }
1399 public override SLE.Expression MakeExpression (BuilderContext ctx)
1401 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1402 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1403 return SLE.Expression.Assign (target, source);
1406 public static string OperName (Mode oper)
1408 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1411 protected override void CloneTo (CloneContext clonectx, Expression t)
1413 UnaryMutator target = (UnaryMutator) t;
1415 target.expr = expr.Clone (clonectx);
1418 public override object Accept (StructuralVisitor visitor)
1420 return visitor.Visit (this);
1426 // Base class for the `is' and `as' operators
1428 public abstract class Probe : Expression
1430 public Expression ProbeType;
1431 protected Expression expr;
1432 protected TypeSpec probe_type_expr;
1434 protected Probe (Expression expr, Expression probe_type, Location l)
1436 ProbeType = probe_type;
1441 public Expression Expr {
1447 public override bool ContainsEmitWithAwait ()
1449 return expr.ContainsEmitWithAwait ();
1452 protected Expression ResolveCommon (ResolveContext rc)
1454 expr = expr.Resolve (rc);
1458 ResolveProbeType (rc);
1459 if (probe_type_expr == null)
1462 if (probe_type_expr.IsStatic) {
1463 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1464 probe_type_expr.GetSignatureForError ());
1468 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1469 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1474 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1475 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1483 protected virtual void ResolveProbeType (ResolveContext rc)
1485 probe_type_expr = ProbeType.ResolveAsType (rc);
1488 public override void EmitSideEffect (EmitContext ec)
1490 expr.EmitSideEffect (ec);
1493 public override void FlowAnalysis (FlowAnalysisContext fc)
1495 expr.FlowAnalysis (fc);
1498 public override bool HasConditionalAccess ()
1500 return expr.HasConditionalAccess ();
1503 protected abstract string OperatorName { get; }
1505 protected override void CloneTo (CloneContext clonectx, Expression t)
1507 Probe target = (Probe) t;
1509 target.expr = expr.Clone (clonectx);
1510 target.ProbeType = ProbeType.Clone (clonectx);
1516 /// Implementation of the `is' operator.
1518 public class Is : Probe
1520 Nullable.Unwrap expr_unwrap;
1521 MethodSpec number_mg;
1522 Arguments number_args;
1524 public Is (Expression expr, Expression probe_type, Location l)
1525 : base (expr, probe_type, l)
1529 protected override string OperatorName {
1530 get { return "is"; }
1533 public LocalVariable Variable { get; set; }
1535 public override Expression CreateExpressionTree (ResolveContext ec)
1537 if (Variable != null)
1538 throw new NotSupportedException ();
1540 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1541 expr.CreateExpressionTree (ec),
1542 new TypeOf (probe_type_expr, loc));
1544 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1547 Expression CreateConstantResult (ResolveContext rc, bool result)
1550 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1551 probe_type_expr.GetSignatureForError ());
1553 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1554 probe_type_expr.GetSignatureForError ());
1556 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1557 return expr.IsSideEffectFree ?
1558 ReducedExpression.Create (c, this) :
1559 new SideEffectConstant (c, this, loc);
1562 public override void Emit (EmitContext ec)
1564 if (probe_type_expr == null) {
1565 if (ProbeType is WildcardPattern) {
1566 expr.EmitSideEffect (ec);
1567 ProbeType.Emit (ec);
1569 EmitPatternMatch (ec);
1576 if (expr_unwrap == null) {
1578 ec.Emit (OpCodes.Cgt_Un);
1582 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1584 if (probe_type_expr == null) {
1585 EmitPatternMatch (ec);
1590 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1593 void EmitPatternMatch (EmitContext ec)
1595 var no_match = ec.DefineLabel ();
1596 var end = ec.DefineLabel ();
1598 if (expr_unwrap != null) {
1599 expr_unwrap.EmitCheck (ec);
1601 if (ProbeType.IsNull) {
1603 ec.Emit (OpCodes.Ceq);
1607 ec.Emit (OpCodes.Brfalse_S, no_match);
1608 expr_unwrap.Emit (ec);
1609 ProbeType.Emit (ec);
1610 ec.Emit (OpCodes.Ceq);
1611 ec.Emit (OpCodes.Br_S, end);
1612 ec.MarkLabel (no_match);
1618 if (number_args != null && number_args.Count == 3) {
1619 var ce = new CallEmitter ();
1620 ce.Emit (ec, number_mg, number_args, loc);
1624 var probe_type = ProbeType.Type;
1627 ec.Emit (OpCodes.Isinst, probe_type);
1628 ec.Emit (OpCodes.Dup);
1629 ec.Emit (OpCodes.Brfalse, no_match);
1631 bool complex_pattern = ProbeType is ComplexPatternExpression;
1632 Label prev = ec.RecursivePatternLabel;
1633 if (complex_pattern)
1634 ec.RecursivePatternLabel = ec.DefineLabel ();
1636 if (number_mg != null) {
1637 var ce = new CallEmitter ();
1638 ce.Emit (ec, number_mg, number_args, loc);
1640 if (TypeSpec.IsValueType (probe_type))
1641 ec.Emit (OpCodes.Unbox_Any, probe_type);
1643 ProbeType.Emit (ec);
1644 if (complex_pattern) {
1647 ec.Emit (OpCodes.Ceq);
1650 ec.Emit (OpCodes.Br_S, end);
1651 ec.MarkLabel (no_match);
1653 ec.Emit (OpCodes.Pop);
1655 if (complex_pattern)
1656 ec.MarkLabel (ec.RecursivePatternLabel);
1658 ec.RecursivePatternLabel = prev;
1664 void EmitLoad (EmitContext ec)
1666 Label no_value_label = new Label ();
1668 if (expr_unwrap != null) {
1669 expr_unwrap.EmitCheck (ec);
1671 if (Variable == null)
1674 ec.Emit (OpCodes.Dup);
1675 no_value_label = ec.DefineLabel ();
1676 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1677 expr_unwrap.Emit (ec);
1681 // Only to make verifier happy
1682 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1683 ec.Emit (OpCodes.Box, expr.Type);
1685 ec.Emit (OpCodes.Isinst, probe_type_expr);
1688 if (Variable != null) {
1689 bool value_on_stack;
1690 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1691 ec.Emit (OpCodes.Dup);
1692 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1693 value_on_stack = true;
1695 value_on_stack = false;
1698 Variable.CreateBuilder (ec);
1699 Variable.EmitAssign (ec);
1701 if (expr_unwrap != null) {
1702 ec.MarkLabel (no_value_label);
1703 } else if (!value_on_stack) {
1709 protected override Expression DoResolve (ResolveContext rc)
1711 if (ResolveCommon (rc) == null)
1714 type = rc.BuiltinTypes.Bool;
1715 eclass = ExprClass.Value;
1717 if (probe_type_expr == null)
1718 return ResolveMatchingExpression (rc);
1720 var res = ResolveResultExpression (rc);
1721 if (Variable != null) {
1722 if (res is Constant)
1723 throw new NotImplementedException ("constant in type pattern matching");
1725 Variable.Type = probe_type_expr;
1726 var bc = rc as BlockContext;
1728 Variable.PrepareAssignmentAnalysis (bc);
1734 public override void FlowAnalysis (FlowAnalysisContext fc)
1736 base.FlowAnalysis (fc);
1738 if (Variable != null)
1739 fc.SetVariableAssigned (Variable.VariableInfo, true);
1742 protected override void ResolveProbeType (ResolveContext rc)
1744 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1745 if (ProbeType is PatternExpression) {
1746 ProbeType.Resolve (rc);
1751 // Have to use session recording because we don't have reliable type probing
1752 // mechanism (similar issue as in attributes resolving)
1754 // TODO: This is still wrong because ResolveAsType can be destructive
1756 var type_printer = new SessionReportPrinter ();
1757 var prev_recorder = rc.Report.SetPrinter (type_printer);
1759 probe_type_expr = ProbeType.ResolveAsType (rc);
1760 type_printer.EndSession ();
1762 if (probe_type_expr != null) {
1763 type_printer.Merge (rc.Report.Printer);
1764 rc.Report.SetPrinter (prev_recorder);
1768 var vexpr = ProbeType as VarExpr;
1769 if (vexpr != null && vexpr.InferType (rc, expr)) {
1770 probe_type_expr = vexpr.Type;
1771 rc.Report.SetPrinter (prev_recorder);
1775 var expr_printer = new SessionReportPrinter ();
1776 rc.Report.SetPrinter (expr_printer);
1777 ProbeType = ProbeType.Resolve (rc);
1778 expr_printer.EndSession ();
1780 if (ProbeType != null) {
1781 expr_printer.Merge (rc.Report.Printer);
1783 type_printer.Merge (rc.Report.Printer);
1786 rc.Report.SetPrinter (prev_recorder);
1790 base.ResolveProbeType (rc);
1793 Expression ResolveMatchingExpression (ResolveContext rc)
1795 var mc = ProbeType as Constant;
1797 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1798 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1803 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1805 var c = Expr as Constant;
1807 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1812 if (Expr.Type.IsNullableType) {
1813 expr_unwrap = new Nullable.Unwrap (Expr);
1814 expr_unwrap.Resolve (rc);
1815 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1816 } else if (ProbeType.Type == Expr.Type) {
1817 // TODO: Better error handling
1818 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1819 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1820 var helper = rc.Module.CreatePatterMatchingHelper ();
1821 number_mg = helper.NumberMatcher.Spec;
1824 // There are actually 3 arguments but the first one is already on the stack
1826 number_args = new Arguments (3);
1827 if (!ProbeType.Type.IsEnum)
1828 number_args.Add (new Argument (Expr));
1830 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1831 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1837 if (ProbeType is PatternExpression) {
1838 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1839 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1845 // TODO: Better error message
1846 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1850 Expression ResolveResultExpression (ResolveContext ec)
1852 TypeSpec d = expr.Type;
1853 bool d_is_nullable = false;
1856 // If E is a method group or the null literal, or if the type of E is a reference
1857 // type or a nullable type and the value of E is null, the result is false
1859 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1860 return CreateConstantResult (ec, false);
1862 if (d.IsNullableType) {
1863 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1864 if (!ut.IsGenericParameter) {
1866 d_is_nullable = true;
1870 TypeSpec t = probe_type_expr;
1871 bool t_is_nullable = false;
1872 if (t.IsNullableType) {
1873 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1874 if (!ut.IsGenericParameter) {
1876 t_is_nullable = true;
1883 // D and T are the same value types but D can be null
1885 if (d_is_nullable && !t_is_nullable) {
1886 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1891 // The result is true if D and T are the same value types
1893 return CreateConstantResult (ec, true);
1896 var tp = d as TypeParameterSpec;
1898 return ResolveGenericParameter (ec, t, tp);
1901 // An unboxing conversion exists
1903 if (Convert.ExplicitReferenceConversionExists (d, t))
1907 // open generic type
1909 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1912 var tps = t as TypeParameterSpec;
1914 return ResolveGenericParameter (ec, d, tps);
1916 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1917 ec.Report.Warning (1981, 3, loc,
1918 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1919 OperatorName, t.GetSignatureForError ());
1922 if (TypeManager.IsGenericParameter (d))
1923 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1925 if (TypeSpec.IsValueType (d)) {
1926 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1927 if (d_is_nullable && !t_is_nullable) {
1928 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1932 return CreateConstantResult (ec, true);
1935 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1936 var c = expr as Constant;
1938 return CreateConstantResult (ec, !c.IsNull);
1941 // Do not optimize for imported type or dynamic type
1943 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1944 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1948 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1952 // Turn is check into simple null check for implicitly convertible reference types
1954 return ReducedExpression.Create (
1955 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1959 if (Convert.ExplicitReferenceConversionExists (d, t))
1963 // open generic type
1965 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1970 return CreateConstantResult (ec, false);
1973 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1975 if (t.IsReferenceType) {
1977 return CreateConstantResult (ec, false);
1980 if (expr.Type.IsGenericParameter) {
1981 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1982 return CreateConstantResult (ec, true);
1984 expr = new BoxedCast (expr, d);
1990 public override object Accept (StructuralVisitor visitor)
1992 return visitor.Visit (this);
1996 class WildcardPattern : PatternExpression
1998 public WildcardPattern (Location loc)
2003 protected override Expression DoResolve (ResolveContext rc)
2005 eclass = ExprClass.Value;
2006 type = rc.BuiltinTypes.Object;
2010 public override void Emit (EmitContext ec)
2016 class RecursivePattern : ComplexPatternExpression
2018 MethodGroupExpr operator_mg;
2019 Arguments operator_args;
2021 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2022 : base (typeExpresion, loc)
2024 Arguments = arguments;
2027 public Arguments Arguments { get; private set; }
2029 protected override Expression DoResolve (ResolveContext rc)
2031 type = TypeExpression.ResolveAsType (rc);
2035 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2036 if (operators == null) {
2037 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2041 var ops = FindMatchingOverloads (operators);
2043 // TODO: better error message
2044 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2049 Arguments.Resolve (rc, out dynamic_args);
2051 throw new NotImplementedException ("dynamic argument");
2053 var op = FindBestOverload (rc, ops);
2055 // TODO: better error message
2056 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2060 var op_types = op.Parameters.Types;
2061 operator_args = new Arguments (op_types.Length);
2062 operator_args.Add (new Argument (new EmptyExpression (type)));
2064 for (int i = 0; i < Arguments.Count; ++i) {
2065 // TODO: Needs releasing optimization
2066 var lt = new LocalTemporary (op_types [i + 1]);
2067 operator_args.Add (new Argument (lt, Argument.AType.Out));
2069 if (comparisons == null)
2070 comparisons = new Expression[Arguments.Count];
2075 var arg = Arguments [i];
2076 var named = arg as NamedArgument;
2077 if (named != null) {
2078 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2079 expr = Arguments [arg_comp_index].Expr;
2085 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2088 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2090 eclass = ExprClass.Value;
2094 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2096 int arg_count = Arguments.Count + 1;
2097 List<MethodSpec> best = null;
2098 foreach (MethodSpec method in members) {
2099 var pm = method.Parameters;
2100 if (pm.Count != arg_count)
2103 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2105 for (int ii = 1; ii < pm.Count; ++ii) {
2106 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2116 best = new List<MethodSpec> ();
2124 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2126 for (int ii = 0; ii < Arguments.Count; ++ii) {
2127 var arg = Arguments [ii];
2128 var expr = arg.Expr;
2129 if (expr is WildcardPattern)
2132 var na = arg as NamedArgument;
2133 for (int i = 0; i < methods.Count; ++i) {
2134 var pd = methods [i].Parameters;
2138 index = pd.GetParameterIndexByName (na.Name);
2140 methods.RemoveAt (i--);
2147 var m = pd.Types [index];
2148 if (!Convert.ImplicitConversionExists (rc, expr, m))
2149 methods.RemoveAt (i--);
2153 if (methods.Count != 1)
2159 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2161 operator_mg.EmitCall (ec, operator_args, false);
2162 ec.Emit (OpCodes.Brfalse, target);
2164 base.EmitBranchable (ec, target, on_true);
2167 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2169 if (expr is WildcardPattern)
2170 return new EmptyExpression (expr.Type);
2172 var recursive = expr as RecursivePattern;
2173 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2177 if (recursive != null) {
2178 recursive.SetParentInstance (lt);
2182 // TODO: Better error handling
2183 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2186 public void SetParentInstance (Expression instance)
2188 operator_args [0] = new Argument (instance);
2192 class PropertyPattern : ComplexPatternExpression
2194 LocalTemporary instance;
2196 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2197 : base (typeExpresion, loc)
2202 public List<PropertyPatternMember> Members { get; private set; }
2204 protected override Expression DoResolve (ResolveContext rc)
2206 type = TypeExpression.ResolveAsType (rc);
2210 comparisons = new Expression[Members.Count];
2212 // TODO: optimize when source is VariableReference, it'd save dup+pop
2213 instance = new LocalTemporary (type);
2215 for (int i = 0; i < Members.Count; i++) {
2216 var lookup = Members [i];
2218 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2219 if (member == null) {
2220 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2221 if (member != null) {
2222 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2227 if (member == null) {
2228 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2232 var pe = member as PropertyExpr;
2233 if (pe == null || member is FieldExpr) {
2234 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2238 // TODO: Obsolete checks
2239 // TODO: check accessibility
2240 if (pe != null && !pe.PropertyInfo.HasGet) {
2241 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2245 var expr = lookup.Expr.Resolve (rc);
2249 var me = (MemberExpr)member;
2250 me.InstanceExpression = instance;
2252 comparisons [i] = ResolveComparison (rc, expr, me);
2255 eclass = ExprClass.Value;
2259 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2261 if (expr is WildcardPattern)
2262 return new EmptyExpression (expr.Type);
2264 return new Is (instance, expr, expr.Location).Resolve (rc);
2267 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2269 instance.Store (ec);
2271 base.EmitBranchable (ec, target, on_true);
2275 class PropertyPatternMember
2277 public PropertyPatternMember (string name, Expression expr, Location loc)
2284 public string Name { get; private set; }
2285 public Expression Expr { get; private set; }
2286 public Location Location { get; private set; }
2289 abstract class PatternExpression : Expression
2291 protected PatternExpression (Location loc)
2296 public override Expression CreateExpressionTree (ResolveContext ec)
2298 throw new NotImplementedException ();
2302 abstract class ComplexPatternExpression : PatternExpression
2304 protected Expression[] comparisons;
2306 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2309 TypeExpression = typeExpresion;
2312 public ATypeNameExpression TypeExpression { get; private set; }
2314 public override void Emit (EmitContext ec)
2316 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2319 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2321 if (comparisons != null) {
2322 foreach (var comp in comparisons) {
2323 comp.EmitBranchable (ec, target, false);
2330 /// Implementation of the `as' operator.
2332 public class As : Probe {
2334 public As (Expression expr, Expression probe_type, Location l)
2335 : base (expr, probe_type, l)
2339 protected override string OperatorName {
2340 get { return "as"; }
2343 public override Expression CreateExpressionTree (ResolveContext ec)
2345 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2346 expr.CreateExpressionTree (ec),
2347 new TypeOf (probe_type_expr, loc));
2349 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2352 public override void Emit (EmitContext ec)
2356 ec.Emit (OpCodes.Isinst, type);
2358 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2359 ec.Emit (OpCodes.Unbox_Any, type);
2362 protected override Expression DoResolve (ResolveContext ec)
2364 if (ResolveCommon (ec) == null)
2367 type = probe_type_expr;
2368 eclass = ExprClass.Value;
2369 TypeSpec etype = expr.Type;
2372 type = InternalType.ErrorType;
2376 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2377 if (TypeManager.IsGenericParameter (type)) {
2378 ec.Report.Error (413, loc,
2379 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2380 probe_type_expr.GetSignatureForError ());
2382 ec.Report.Error (77, loc,
2383 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2384 type.GetSignatureForError ());
2389 if (expr.IsNull && type.IsNullableType) {
2390 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2393 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2394 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2398 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2400 e = EmptyCast.Create (e, type);
2401 return ReducedExpression.Create (e, this).Resolve (ec);
2404 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2405 if (TypeManager.IsGenericParameter (etype))
2406 expr = new BoxedCast (expr, etype);
2411 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2412 expr = new BoxedCast (expr, etype);
2416 if (etype != InternalType.ErrorType) {
2417 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2418 etype.GetSignatureForError (), type.GetSignatureForError ());
2424 public override object Accept (StructuralVisitor visitor)
2426 return visitor.Visit (this);
2431 // This represents a typecast in the source language.
2433 public class Cast : ShimExpression {
2434 Expression target_type;
2436 public Cast (Expression cast_type, Expression expr, Location loc)
2439 this.target_type = cast_type;
2443 public Expression TargetType {
2444 get { return target_type; }
2447 protected override Expression DoResolve (ResolveContext ec)
2449 expr = expr.Resolve (ec);
2453 type = target_type.ResolveAsType (ec);
2457 if (type.IsStatic) {
2458 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2462 if (type.IsPointer) {
2463 if (ec.CurrentIterator != null) {
2464 UnsafeInsideIteratorError (ec, loc);
2465 } else if (!ec.IsUnsafe) {
2466 UnsafeError (ec, loc);
2470 eclass = ExprClass.Value;
2472 Constant c = expr as Constant;
2474 c = c.Reduce (ec, type);
2479 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2481 return EmptyCast.Create (res, type);
2486 protected override void CloneTo (CloneContext clonectx, Expression t)
2488 Cast target = (Cast) t;
2490 target.target_type = target_type.Clone (clonectx);
2491 target.expr = expr.Clone (clonectx);
2494 public override object Accept (StructuralVisitor visitor)
2496 return visitor.Visit (this);
2500 public class ImplicitCast : ShimExpression
2504 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2507 this.loc = expr.Location;
2509 this.arrayAccess = arrayAccess;
2512 protected override Expression DoResolve (ResolveContext ec)
2514 expr = expr.Resolve (ec);
2519 expr = ConvertExpressionToArrayIndex (ec, expr);
2521 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2527 public class DeclarationExpression : Expression, IMemoryLocation
2529 LocalVariableReference lvr;
2531 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2533 VariableType = variableType;
2534 Variable = variable;
2535 this.loc = variable.Location;
2538 public LocalVariable Variable { get; set; }
2539 public Expression Initializer { get; set; }
2540 public FullNamedExpression VariableType { get; set; }
2542 public void AddressOf (EmitContext ec, AddressOp mode)
2544 Variable.CreateBuilder (ec);
2546 if (Initializer != null) {
2547 lvr.EmitAssign (ec, Initializer, false, false);
2550 lvr.AddressOf (ec, mode);
2553 protected override void CloneTo (CloneContext clonectx, Expression t)
2555 var target = (DeclarationExpression) t;
2557 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2559 if (Initializer != null)
2560 target.Initializer = Initializer.Clone (clonectx);
2563 public override Expression CreateExpressionTree (ResolveContext rc)
2565 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2569 bool DoResolveCommon (ResolveContext rc)
2571 var var_expr = VariableType as VarExpr;
2572 if (var_expr != null) {
2573 type = InternalType.VarOutType;
2575 type = VariableType.ResolveAsType (rc);
2580 if (Initializer != null) {
2581 Initializer = Initializer.Resolve (rc);
2583 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2584 type = var_expr.Type;
2588 Variable.Type = type;
2589 lvr = new LocalVariableReference (Variable, loc);
2591 eclass = ExprClass.Variable;
2595 protected override Expression DoResolve (ResolveContext rc)
2597 if (DoResolveCommon (rc))
2603 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2605 if (lvr == null && DoResolveCommon (rc))
2606 lvr.ResolveLValue (rc, right_side);
2611 public override void Emit (EmitContext ec)
2613 throw new NotImplementedException ();
2618 // C# 2.0 Default value expression
2620 public class DefaultValueExpression : Expression
2624 public DefaultValueExpression (Expression expr, Location loc)
2630 public Expression Expr {
2636 public override bool IsSideEffectFree {
2642 public override bool ContainsEmitWithAwait ()
2647 public override Expression CreateExpressionTree (ResolveContext ec)
2649 Arguments args = new Arguments (2);
2650 args.Add (new Argument (this));
2651 args.Add (new Argument (new TypeOf (type, loc)));
2652 return CreateExpressionFactoryCall (ec, "Constant", args);
2655 protected override Expression DoResolve (ResolveContext ec)
2657 type = expr.ResolveAsType (ec);
2661 if (type.IsStatic) {
2662 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2666 return new NullLiteral (Location).ConvertImplicitly (type);
2668 if (TypeSpec.IsReferenceType (type))
2669 return new NullConstant (type, loc);
2671 Constant c = New.Constantify (type, expr.Location);
2675 eclass = ExprClass.Variable;
2679 public override void Emit (EmitContext ec)
2681 LocalTemporary temp_storage = new LocalTemporary(type);
2683 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2684 ec.Emit(OpCodes.Initobj, type);
2685 temp_storage.Emit(ec);
2686 temp_storage.Release (ec);
2690 public override SLE.Expression MakeExpression (BuilderContext ctx)
2692 return SLE.Expression.Default (type.GetMetaInfo ());
2696 protected override void CloneTo (CloneContext clonectx, Expression t)
2698 DefaultValueExpression target = (DefaultValueExpression) t;
2700 target.expr = expr.Clone (clonectx);
2703 public override object Accept (StructuralVisitor visitor)
2705 return visitor.Visit (this);
2710 /// Binary operators
2712 public class Binary : Expression, IDynamicBinder
2714 public class PredefinedOperator
2716 protected readonly TypeSpec left;
2717 protected readonly TypeSpec right;
2718 protected readonly TypeSpec left_unwrap;
2719 protected readonly TypeSpec right_unwrap;
2720 public readonly Operator OperatorsMask;
2721 public TypeSpec ReturnType;
2723 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2724 : this (ltype, rtype, op_mask, ltype)
2728 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2729 : this (type, type, op_mask, return_type)
2733 public PredefinedOperator (TypeSpec type, Operator op_mask)
2734 : this (type, type, op_mask, type)
2738 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2740 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2741 throw new InternalErrorException ("Only masked values can be used");
2743 if ((op_mask & Operator.NullableMask) != 0) {
2744 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2745 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2747 left_unwrap = ltype;
2748 right_unwrap = rtype;
2753 this.OperatorsMask = op_mask;
2754 this.ReturnType = return_type;
2757 public bool IsLifted {
2759 return (OperatorsMask & Operator.NullableMask) != 0;
2763 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2767 var left_expr = b.left;
2768 var right_expr = b.right;
2770 b.type = ReturnType;
2773 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2774 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2775 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2778 if (right_expr.IsNull) {
2779 if ((b.oper & Operator.EqualityMask) != 0) {
2780 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2781 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2782 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2783 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2784 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2786 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2787 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2789 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2790 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2792 return b.CreateLiftedValueTypeResult (rc, left);
2794 } else if (left_expr.IsNull) {
2795 if ((b.oper & Operator.EqualityMask) != 0) {
2796 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2797 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2798 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2799 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2800 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2802 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2803 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2805 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2806 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2808 return b.CreateLiftedValueTypeResult (rc, right);
2814 // A user operators does not support multiple user conversions, but decimal type
2815 // is considered to be predefined type therefore we apply predefined operators rules
2816 // and then look for decimal user-operator implementation
2818 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2819 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2820 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2822 return b.ResolveUserOperator (rc, b.left, b.right);
2825 c = right_expr as Constant;
2827 if (c.IsDefaultValue) {
2831 // (expr + 0) to expr
2832 // (expr - 0) to expr
2833 // (bool? | false) to bool?
2835 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2836 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2837 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2838 return ReducedExpression.Create (b.left, b).Resolve (rc);
2842 // Optimizes (value &/&& 0) to 0
2844 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2845 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2846 return ReducedExpression.Create (side_effect, b);
2850 // Optimizes (bool? & true) to bool?
2852 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2853 return ReducedExpression.Create (b.left, b).Resolve (rc);
2857 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2858 return ReducedExpression.Create (b.left, b).Resolve (rc);
2860 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2861 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2865 c = b.left as Constant;
2867 if (c.IsDefaultValue) {
2871 // (0 + expr) to expr
2872 // (false | bool?) to bool?
2874 if (b.oper == Operator.Addition ||
2875 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2876 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2877 return ReducedExpression.Create (b.right, b).Resolve (rc);
2881 // Optimizes (false && expr) to false
2883 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2884 // No rhs side-effects
2885 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2886 return ReducedExpression.Create (c, b);
2890 // Optimizes (0 & value) to 0
2892 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2893 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2894 return ReducedExpression.Create (side_effect, b);
2898 // Optimizes (true & bool?) to bool?
2900 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2901 return ReducedExpression.Create (b.right, b).Resolve (rc);
2905 // Optimizes (true || expr) to true
2907 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2908 // No rhs side-effects
2909 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2910 return ReducedExpression.Create (c, b);
2914 if (b.oper == Operator.Multiply && c.IsOneInteger)
2915 return ReducedExpression.Create (b.right, b).Resolve (rc);
2919 var lifted = new Nullable.LiftedBinaryOperator (b);
2921 TypeSpec ltype, rtype;
2922 if (b.left.Type.IsNullableType) {
2923 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2924 ltype = left_unwrap;
2929 if (b.right.Type.IsNullableType) {
2930 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2931 rtype = right_unwrap;
2936 lifted.Left = b.left.IsNull ?
2937 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2938 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2940 lifted.Right = b.right.IsNull ?
2941 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2942 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2944 return lifted.Resolve (rc);
2947 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2948 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2953 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2956 // We are dealing with primitive types only
2958 return left == ltype && ltype == rtype;
2961 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2964 if (left == lexpr.Type && right == rexpr.Type)
2967 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2968 Convert.ImplicitConversionExists (ec, rexpr, right);
2971 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2973 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2974 return best_operator;
2976 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2980 if (left != null && best_operator.left != null) {
2981 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2985 // When second argument is same as the first one, the result is same
2987 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2988 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2991 if (result == 0 || result > 2)
2994 return result == 1 ? best_operator : this;
2998 sealed class PredefinedStringOperator : PredefinedOperator
3000 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3001 : base (type, type, op_mask, retType)
3005 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3006 : base (ltype, rtype, op_mask, retType)
3010 public override Expression ConvertResult (ResolveContext ec, Binary b)
3013 // Use original expression for nullable arguments
3015 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3017 b.left = unwrap.Original;
3019 unwrap = b.right as Nullable.Unwrap;
3021 b.right = unwrap.Original;
3023 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3024 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3027 // Start a new concat expression using converted expression
3029 return StringConcat.Create (ec, b.left, b.right, b.loc);
3033 sealed class PredefinedEqualityOperator : PredefinedOperator
3035 MethodSpec equal_method, inequal_method;
3037 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3038 : base (arg, arg, Operator.EqualityMask, retType)
3042 public override Expression ConvertResult (ResolveContext ec, Binary b)
3044 b.type = ReturnType;
3046 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3047 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3049 Arguments args = new Arguments (2);
3050 args.Add (new Argument (b.left));
3051 args.Add (new Argument (b.right));
3054 if (b.oper == Operator.Equality) {
3055 if (equal_method == null) {
3056 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3057 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3058 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3059 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3061 throw new NotImplementedException (left.GetSignatureForError ());
3064 method = equal_method;
3066 if (inequal_method == null) {
3067 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3068 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3069 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3070 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3072 throw new NotImplementedException (left.GetSignatureForError ());
3075 method = inequal_method;
3078 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3082 class PredefinedPointerOperator : PredefinedOperator
3084 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3085 : base (ltype, rtype, op_mask)
3089 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3090 : base (ltype, rtype, op_mask, retType)
3094 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3095 : base (type, op_mask, return_type)
3099 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3102 if (!lexpr.Type.IsPointer)
3105 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3109 if (right == null) {
3110 if (!rexpr.Type.IsPointer)
3113 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3120 public override Expression ConvertResult (ResolveContext ec, Binary b)
3123 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3124 } else if (right != null) {
3125 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3128 TypeSpec r_type = ReturnType;
3129 Expression left_arg, right_arg;
3130 if (r_type == null) {
3133 right_arg = b.right;
3134 r_type = b.left.Type;
3138 r_type = b.right.Type;
3142 right_arg = b.right;
3145 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3150 public enum Operator {
3151 Multiply = 0 | ArithmeticMask,
3152 Division = 1 | ArithmeticMask,
3153 Modulus = 2 | ArithmeticMask,
3154 Addition = 3 | ArithmeticMask | AdditionMask,
3155 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3157 LeftShift = 5 | ShiftMask,
3158 RightShift = 6 | ShiftMask,
3160 LessThan = 7 | ComparisonMask | RelationalMask,
3161 GreaterThan = 8 | ComparisonMask | RelationalMask,
3162 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3163 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3164 Equality = 11 | ComparisonMask | EqualityMask,
3165 Inequality = 12 | ComparisonMask | EqualityMask,
3167 BitwiseAnd = 13 | BitwiseMask,
3168 ExclusiveOr = 14 | BitwiseMask,
3169 BitwiseOr = 15 | BitwiseMask,
3171 LogicalAnd = 16 | LogicalMask,
3172 LogicalOr = 17 | LogicalMask,
3177 ValuesOnlyMask = ArithmeticMask - 1,
3178 ArithmeticMask = 1 << 5,
3180 ComparisonMask = 1 << 7,
3181 EqualityMask = 1 << 8,
3182 BitwiseMask = 1 << 9,
3183 LogicalMask = 1 << 10,
3184 AdditionMask = 1 << 11,
3185 SubtractionMask = 1 << 12,
3186 RelationalMask = 1 << 13,
3188 DecomposedMask = 1 << 19,
3189 NullableMask = 1 << 20
3193 public enum State : byte
3197 UserOperatorsExcluded = 1 << 2
3200 readonly Operator oper;
3201 Expression left, right;
3203 ConvCast.Mode enum_conversion;
3205 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3206 : this (oper, left, right, State.Compound)
3210 public Binary (Operator oper, Expression left, Expression right, State state)
3211 : this (oper, left, right)
3216 public Binary (Operator oper, Expression left, Expression right)
3217 : this (oper, left, right, left.Location)
3221 public Binary (Operator oper, Expression left, Expression right, Location loc)
3231 public bool IsCompound {
3233 return (state & State.Compound) != 0;
3237 public Operator Oper {
3243 public Expression Left {
3249 public Expression Right {
3255 public override Location StartLocation {
3257 return left.StartLocation;
3264 /// Returns a stringified representation of the Operator
3266 string OperName (Operator oper)
3270 case Operator.Multiply:
3273 case Operator.Division:
3276 case Operator.Modulus:
3279 case Operator.Addition:
3282 case Operator.Subtraction:
3285 case Operator.LeftShift:
3288 case Operator.RightShift:
3291 case Operator.LessThan:
3294 case Operator.GreaterThan:
3297 case Operator.LessThanOrEqual:
3300 case Operator.GreaterThanOrEqual:
3303 case Operator.Equality:
3306 case Operator.Inequality:
3309 case Operator.BitwiseAnd:
3312 case Operator.BitwiseOr:
3315 case Operator.ExclusiveOr:
3318 case Operator.LogicalOr:
3321 case Operator.LogicalAnd:
3325 s = oper.ToString ();
3335 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3337 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3340 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3342 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3346 l = left.Type.GetSignatureForError ();
3347 r = right.Type.GetSignatureForError ();
3349 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3353 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3355 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3358 public override void FlowAnalysis (FlowAnalysisContext fc)
3361 // Optimized version when on-true/on-false data are not needed
3363 if ((oper & Operator.LogicalMask) == 0) {
3364 left.FlowAnalysis (fc);
3365 right.FlowAnalysis (fc);
3369 left.FlowAnalysisConditional (fc);
3370 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3371 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3373 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3374 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3375 right.FlowAnalysisConditional (fc);
3377 if (oper == Operator.LogicalOr)
3378 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3380 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3383 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3385 if ((oper & Operator.LogicalMask) == 0) {
3386 base.FlowAnalysisConditional (fc);
3390 left.FlowAnalysisConditional (fc);
3391 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3392 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3394 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3395 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3396 right.FlowAnalysisConditional (fc);
3398 var lc = left as Constant;
3399 if (oper == Operator.LogicalOr) {
3400 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3401 if (lc != null && lc.IsDefaultValue)
3402 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3404 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3406 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3407 if (lc != null && !lc.IsDefaultValue)
3408 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3410 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3415 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3417 string GetOperatorExpressionTypeName ()
3420 case Operator.Addition:
3421 return IsCompound ? "AddAssign" : "Add";
3422 case Operator.BitwiseAnd:
3423 return IsCompound ? "AndAssign" : "And";
3424 case Operator.BitwiseOr:
3425 return IsCompound ? "OrAssign" : "Or";
3426 case Operator.Division:
3427 return IsCompound ? "DivideAssign" : "Divide";
3428 case Operator.ExclusiveOr:
3429 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3430 case Operator.Equality:
3432 case Operator.GreaterThan:
3433 return "GreaterThan";
3434 case Operator.GreaterThanOrEqual:
3435 return "GreaterThanOrEqual";
3436 case Operator.Inequality:
3438 case Operator.LeftShift:
3439 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3440 case Operator.LessThan:
3442 case Operator.LessThanOrEqual:
3443 return "LessThanOrEqual";
3444 case Operator.LogicalAnd:
3446 case Operator.LogicalOr:
3448 case Operator.Modulus:
3449 return IsCompound ? "ModuloAssign" : "Modulo";
3450 case Operator.Multiply:
3451 return IsCompound ? "MultiplyAssign" : "Multiply";
3452 case Operator.RightShift:
3453 return IsCompound ? "RightShiftAssign" : "RightShift";
3454 case Operator.Subtraction:
3455 return IsCompound ? "SubtractAssign" : "Subtract";
3457 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3461 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3464 case Operator.Addition:
3465 return CSharp.Operator.OpType.Addition;
3466 case Operator.BitwiseAnd:
3467 case Operator.LogicalAnd:
3468 return CSharp.Operator.OpType.BitwiseAnd;
3469 case Operator.BitwiseOr:
3470 case Operator.LogicalOr:
3471 return CSharp.Operator.OpType.BitwiseOr;
3472 case Operator.Division:
3473 return CSharp.Operator.OpType.Division;
3474 case Operator.Equality:
3475 return CSharp.Operator.OpType.Equality;
3476 case Operator.ExclusiveOr:
3477 return CSharp.Operator.OpType.ExclusiveOr;
3478 case Operator.GreaterThan:
3479 return CSharp.Operator.OpType.GreaterThan;
3480 case Operator.GreaterThanOrEqual:
3481 return CSharp.Operator.OpType.GreaterThanOrEqual;
3482 case Operator.Inequality:
3483 return CSharp.Operator.OpType.Inequality;
3484 case Operator.LeftShift:
3485 return CSharp.Operator.OpType.LeftShift;
3486 case Operator.LessThan:
3487 return CSharp.Operator.OpType.LessThan;
3488 case Operator.LessThanOrEqual:
3489 return CSharp.Operator.OpType.LessThanOrEqual;
3490 case Operator.Modulus:
3491 return CSharp.Operator.OpType.Modulus;
3492 case Operator.Multiply:
3493 return CSharp.Operator.OpType.Multiply;
3494 case Operator.RightShift:
3495 return CSharp.Operator.OpType.RightShift;
3496 case Operator.Subtraction:
3497 return CSharp.Operator.OpType.Subtraction;
3499 throw new InternalErrorException (op.ToString ());
3503 public override bool ContainsEmitWithAwait ()
3505 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3508 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3513 case Operator.Multiply:
3514 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3515 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3516 opcode = OpCodes.Mul_Ovf;
3517 else if (!IsFloat (l))
3518 opcode = OpCodes.Mul_Ovf_Un;
3520 opcode = OpCodes.Mul;
3522 opcode = OpCodes.Mul;
3526 case Operator.Division:
3528 opcode = OpCodes.Div_Un;
3530 opcode = OpCodes.Div;
3533 case Operator.Modulus:
3535 opcode = OpCodes.Rem_Un;
3537 opcode = OpCodes.Rem;
3540 case Operator.Addition:
3541 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3542 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3543 opcode = OpCodes.Add_Ovf;
3544 else if (!IsFloat (l))
3545 opcode = OpCodes.Add_Ovf_Un;
3547 opcode = OpCodes.Add;
3549 opcode = OpCodes.Add;
3552 case Operator.Subtraction:
3553 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3554 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3555 opcode = OpCodes.Sub_Ovf;
3556 else if (!IsFloat (l))
3557 opcode = OpCodes.Sub_Ovf_Un;
3559 opcode = OpCodes.Sub;
3561 opcode = OpCodes.Sub;
3564 case Operator.RightShift:
3565 if (!(right is IntConstant)) {
3566 ec.EmitInt (GetShiftMask (l));
3567 ec.Emit (OpCodes.And);
3571 opcode = OpCodes.Shr_Un;
3573 opcode = OpCodes.Shr;
3576 case Operator.LeftShift:
3577 if (!(right is IntConstant)) {
3578 ec.EmitInt (GetShiftMask (l));
3579 ec.Emit (OpCodes.And);
3582 opcode = OpCodes.Shl;
3585 case Operator.Equality:
3586 opcode = OpCodes.Ceq;
3589 case Operator.Inequality:
3590 ec.Emit (OpCodes.Ceq);
3593 opcode = OpCodes.Ceq;
3596 case Operator.LessThan:
3598 opcode = OpCodes.Clt_Un;
3600 opcode = OpCodes.Clt;
3603 case Operator.GreaterThan:
3605 opcode = OpCodes.Cgt_Un;
3607 opcode = OpCodes.Cgt;
3610 case Operator.LessThanOrEqual:
3611 if (IsUnsigned (l) || IsFloat (l))
3612 ec.Emit (OpCodes.Cgt_Un);
3614 ec.Emit (OpCodes.Cgt);
3617 opcode = OpCodes.Ceq;
3620 case Operator.GreaterThanOrEqual:
3621 if (IsUnsigned (l) || IsFloat (l))
3622 ec.Emit (OpCodes.Clt_Un);
3624 ec.Emit (OpCodes.Clt);
3628 opcode = OpCodes.Ceq;
3631 case Operator.BitwiseOr:
3632 opcode = OpCodes.Or;
3635 case Operator.BitwiseAnd:
3636 opcode = OpCodes.And;
3639 case Operator.ExclusiveOr:
3640 opcode = OpCodes.Xor;
3644 throw new InternalErrorException (oper.ToString ());
3650 static int GetShiftMask (TypeSpec type)
3652 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3655 static bool IsUnsigned (TypeSpec t)
3657 switch (t.BuiltinType) {
3658 case BuiltinTypeSpec.Type.Char:
3659 case BuiltinTypeSpec.Type.UInt:
3660 case BuiltinTypeSpec.Type.ULong:
3661 case BuiltinTypeSpec.Type.UShort:
3662 case BuiltinTypeSpec.Type.Byte:
3669 static bool IsFloat (TypeSpec t)
3671 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3674 public Expression ResolveOperator (ResolveContext rc)
3676 eclass = ExprClass.Value;
3678 TypeSpec l = left.Type;
3679 TypeSpec r = right.Type;
3681 bool primitives_only = false;
3684 // Handles predefined primitive types
3686 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3687 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3688 if ((oper & Operator.ShiftMask) == 0) {
3689 if (!DoBinaryOperatorPromotion (rc))
3692 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3696 if (l.IsPointer || r.IsPointer)
3697 return ResolveOperatorPointer (rc, l, r);
3700 if ((state & State.UserOperatorsExcluded) == 0) {
3701 expr = ResolveUserOperator (rc, left, right);
3706 bool lenum = l.IsEnum;
3707 bool renum = r.IsEnum;
3708 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3712 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3713 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3718 if ((oper & Operator.BitwiseMask) != 0) {
3719 expr = EmptyCast.Create (expr, type);
3720 enum_conversion = GetEnumResultCast (type);
3722 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3723 expr = OptimizeAndOperation (expr);
3727 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3728 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3731 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3732 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3736 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3739 // We cannot break here there is also Enum + String possible match
3740 // which is not ambiguous with predefined enum operators
3743 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3744 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3748 } else if (l.IsDelegate || r.IsDelegate) {
3752 expr = ResolveOperatorDelegate (rc, l, r);
3754 // TODO: Can this be ambiguous
3762 // Equality operators are more complicated
3764 if ((oper & Operator.EqualityMask) != 0) {
3765 return ResolveEquality (rc, l, r, primitives_only);
3768 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3772 if (primitives_only)
3776 // Lifted operators have lower priority
3778 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3781 static bool IsEnumOrNullableEnum (TypeSpec type)
3783 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3787 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3788 // if 'left' is not an enumeration constant, create one from the type of 'right'
3789 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3792 case Operator.BitwiseOr:
3793 case Operator.BitwiseAnd:
3794 case Operator.ExclusiveOr:
3795 case Operator.Equality:
3796 case Operator.Inequality:
3797 case Operator.LessThan:
3798 case Operator.LessThanOrEqual:
3799 case Operator.GreaterThan:
3800 case Operator.GreaterThanOrEqual:
3801 if (left.Type.IsEnum)
3804 if (left.IsZeroInteger)
3805 return left.Reduce (ec, right.Type);
3809 case Operator.Addition:
3810 case Operator.Subtraction:
3813 case Operator.Multiply:
3814 case Operator.Division:
3815 case Operator.Modulus:
3816 case Operator.LeftShift:
3817 case Operator.RightShift:
3818 if (right.Type.IsEnum || left.Type.IsEnum)
3827 // The `|' operator used on types which were extended is dangerous
3829 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3831 OpcodeCast lcast = left as OpcodeCast;
3832 if (lcast != null) {
3833 if (IsUnsigned (lcast.UnderlyingType))
3837 OpcodeCast rcast = right as OpcodeCast;
3838 if (rcast != null) {
3839 if (IsUnsigned (rcast.UnderlyingType))
3843 if (lcast == null && rcast == null)
3846 // FIXME: consider constants
3848 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3849 ec.Report.Warning (675, 3, loc,
3850 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3851 ltype.GetSignatureForError ());
3854 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3856 return new PredefinedOperator[] {
3858 // Pointer arithmetic:
3860 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3861 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3862 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3863 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3865 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3866 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3867 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3868 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3871 // T* operator + (int y, T* x);
3872 // T* operator + (uint y, T *x);
3873 // T* operator + (long y, T *x);
3874 // T* operator + (ulong y, T *x);
3876 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3877 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3878 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3879 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3882 // long operator - (T* x, T *y)
3884 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3888 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3890 TypeSpec bool_type = types.Bool;
3893 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3894 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3895 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3896 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3897 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3898 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3899 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3901 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3902 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3903 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3904 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3905 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3906 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3907 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3909 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3910 // Remaining string operators are in lifted tables
3912 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3914 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3915 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3916 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3920 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3922 var types = module.Compiler.BuiltinTypes;
3925 // Not strictly lifted but need to be in second group otherwise expressions like
3926 // int + null would resolve to +(object, string) instead of +(int?, int?)
3928 var string_operators = new [] {
3929 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3930 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3933 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3934 if (nullable == null)
3935 return string_operators;
3937 var bool_type = types.Bool;
3939 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3940 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3941 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3942 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3943 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3944 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3945 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3946 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3949 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3950 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3951 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3952 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3953 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3954 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3955 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3957 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3958 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3959 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3960 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3961 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3962 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3963 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3965 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3967 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3968 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3969 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3971 string_operators [0],
3972 string_operators [1]
3976 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3978 TypeSpec bool_type = types.Bool;
3981 new PredefinedEqualityOperator (types.String, bool_type),
3982 new PredefinedEqualityOperator (types.Delegate, bool_type),
3983 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3984 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3985 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3986 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3987 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3988 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3989 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3990 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3994 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3996 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3998 if (nullable == null)
3999 return new PredefinedOperator [0];
4001 var types = module.Compiler.BuiltinTypes;
4002 var bool_type = types.Bool;
4003 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4004 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4005 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4006 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4007 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4008 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4009 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4010 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4013 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4014 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4015 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4016 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4017 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4018 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4019 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4020 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4025 // 7.2.6.2 Binary numeric promotions
4027 bool DoBinaryOperatorPromotion (ResolveContext rc)
4029 TypeSpec ltype = left.Type;
4030 if (ltype.IsNullableType) {
4031 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4035 // This is numeric promotion code only
4037 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4040 TypeSpec rtype = right.Type;
4041 if (rtype.IsNullableType) {
4042 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4045 var lb = ltype.BuiltinType;
4046 var rb = rtype.BuiltinType;
4050 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4051 type = rc.BuiltinTypes.Decimal;
4052 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4053 type = rc.BuiltinTypes.Double;
4054 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4055 type = rc.BuiltinTypes.Float;
4056 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4057 type = rc.BuiltinTypes.ULong;
4059 if (IsSignedType (lb)) {
4060 expr = ConvertSignedConstant (left, type);
4064 } else if (IsSignedType (rb)) {
4065 expr = ConvertSignedConstant (right, type);
4071 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4072 type = rc.BuiltinTypes.Long;
4073 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4074 type = rc.BuiltinTypes.UInt;
4076 if (IsSignedType (lb)) {
4077 expr = ConvertSignedConstant (left, type);
4079 type = rc.BuiltinTypes.Long;
4080 } else if (IsSignedType (rb)) {
4081 expr = ConvertSignedConstant (right, type);
4083 type = rc.BuiltinTypes.Long;
4086 type = rc.BuiltinTypes.Int;
4089 if (ltype != type) {
4090 expr = PromoteExpression (rc, left, type);
4097 if (rtype != type) {
4098 expr = PromoteExpression (rc, right, type);
4108 static bool IsSignedType (BuiltinTypeSpec.Type type)
4111 case BuiltinTypeSpec.Type.Int:
4112 case BuiltinTypeSpec.Type.Short:
4113 case BuiltinTypeSpec.Type.SByte:
4114 case BuiltinTypeSpec.Type.Long:
4121 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4123 var c = expr as Constant;
4127 return c.ConvertImplicitly (type);
4130 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4132 if (expr.Type.IsNullableType) {
4133 return Convert.ImplicitConversionStandard (rc, expr,
4134 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4137 var c = expr as Constant;
4139 return c.ConvertImplicitly (type);
4141 return Convert.ImplicitNumericConversion (expr, type);
4144 protected override Expression DoResolve (ResolveContext ec)
4149 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4150 left = ((ParenthesizedExpression) left).Expr;
4151 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4155 if (left.eclass == ExprClass.Type) {
4156 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4160 left = left.Resolve (ec);
4165 right = right.Resolve (ec);
4169 Constant lc = left as Constant;
4170 Constant rc = right as Constant;
4172 // The conversion rules are ignored in enum context but why
4173 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4174 lc = EnumLiftUp (ec, lc, rc);
4176 rc = EnumLiftUp (ec, rc, lc);
4179 if (rc != null && lc != null) {
4180 int prev_e = ec.Report.Errors;
4181 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4182 if (e != null || ec.Report.Errors != prev_e)
4186 // Comparison warnings
4187 if ((oper & Operator.ComparisonMask) != 0) {
4188 if (left.Equals (right)) {
4189 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4191 CheckOutOfRangeComparison (ec, lc, right.Type);
4192 CheckOutOfRangeComparison (ec, rc, left.Type);
4195 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4196 return DoResolveDynamic (ec);
4198 return DoResolveCore (ec, left, right);
4201 Expression DoResolveDynamic (ResolveContext rc)
4204 var rt = right.Type;
4205 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4206 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4207 Error_OperatorCannotBeApplied (rc, left, right);
4214 // Special handling for logical boolean operators which require rhs not to be
4215 // evaluated based on lhs value
4217 if ((oper & Operator.LogicalMask) != 0) {
4218 Expression cond_left, cond_right, expr;
4220 args = new Arguments (2);
4222 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4223 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4225 var cond_args = new Arguments (1);
4226 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4229 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4230 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4232 left = temp.CreateReferenceExpression (rc, loc);
4233 if (oper == Operator.LogicalAnd) {
4234 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4237 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4241 args.Add (new Argument (left));
4242 args.Add (new Argument (right));
4243 cond_right = new DynamicExpressionStatement (this, args, loc);
4245 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4247 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4248 rc.Report.Error (7083, left.Location,
4249 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4250 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4254 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4255 args.Add (new Argument (right));
4256 right = new DynamicExpressionStatement (this, args, loc);
4259 // bool && dynamic => (temp = left) ? temp && right : temp;
4260 // bool || dynamic => (temp = left) ? temp : temp || right;
4262 if (oper == Operator.LogicalAnd) {
4264 cond_right = temp.CreateReferenceExpression (rc, loc);
4266 cond_left = temp.CreateReferenceExpression (rc, loc);
4270 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4273 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4276 args = new Arguments (2);
4277 args.Add (new Argument (left));
4278 args.Add (new Argument (right));
4279 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4282 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4284 Expression expr = ResolveOperator (ec);
4286 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4288 if (left == null || right == null)
4289 throw new InternalErrorException ("Invalid conversion");
4291 if (oper == Operator.BitwiseOr)
4292 CheckBitwiseOrOnSignExtended (ec);
4297 public override SLE.Expression MakeExpression (BuilderContext ctx)
4299 return MakeExpression (ctx, left, right);
4302 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4304 var le = left.MakeExpression (ctx);
4305 var re = right.MakeExpression (ctx);
4306 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4309 case Operator.Addition:
4310 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4311 case Operator.BitwiseAnd:
4312 return SLE.Expression.And (le, re);
4313 case Operator.BitwiseOr:
4314 return SLE.Expression.Or (le, re);
4315 case Operator.Division:
4316 return SLE.Expression.Divide (le, re);
4317 case Operator.Equality:
4318 return SLE.Expression.Equal (le, re);
4319 case Operator.ExclusiveOr:
4320 return SLE.Expression.ExclusiveOr (le, re);
4321 case Operator.GreaterThan:
4322 return SLE.Expression.GreaterThan (le, re);
4323 case Operator.GreaterThanOrEqual:
4324 return SLE.Expression.GreaterThanOrEqual (le, re);
4325 case Operator.Inequality:
4326 return SLE.Expression.NotEqual (le, re);
4327 case Operator.LeftShift:
4328 return SLE.Expression.LeftShift (le, re);
4329 case Operator.LessThan:
4330 return SLE.Expression.LessThan (le, re);
4331 case Operator.LessThanOrEqual:
4332 return SLE.Expression.LessThanOrEqual (le, re);
4333 case Operator.LogicalAnd:
4334 return SLE.Expression.AndAlso (le, re);
4335 case Operator.LogicalOr:
4336 return SLE.Expression.OrElse (le, re);
4337 case Operator.Modulus:
4338 return SLE.Expression.Modulo (le, re);
4339 case Operator.Multiply:
4340 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4341 case Operator.RightShift:
4342 return SLE.Expression.RightShift (le, re);
4343 case Operator.Subtraction:
4344 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4346 throw new NotImplementedException (oper.ToString ());
4351 // D operator + (D x, D y)
4352 // D operator - (D x, D y)
4354 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4356 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4358 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4359 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4364 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4365 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4375 MethodSpec method = null;
4376 Arguments args = new Arguments (2);
4377 args.Add (new Argument (left));
4378 args.Add (new Argument (right));
4380 if (oper == Operator.Addition) {
4381 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4382 } else if (oper == Operator.Subtraction) {
4383 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4387 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4389 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4390 return new ClassCast (expr, l);
4394 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4396 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4399 // bool operator == (E x, E y);
4400 // bool operator != (E x, E y);
4401 // bool operator < (E x, E y);
4402 // bool operator > (E x, E y);
4403 // bool operator <= (E x, E y);
4404 // bool operator >= (E x, E y);
4406 // E operator & (E x, E y);
4407 // E operator | (E x, E y);
4408 // E operator ^ (E x, E y);
4411 if ((oper & Operator.ComparisonMask) != 0) {
4412 type = rc.BuiltinTypes.Bool;
4418 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4424 if (ltype == rtype) {
4428 var lifted = new Nullable.LiftedBinaryOperator (this);
4430 lifted.Right = right;
4431 return lifted.Resolve (rc);
4434 if (renum && !ltype.IsNullableType) {
4435 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4440 } else if (lenum && !rtype.IsNullableType) {
4441 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4449 // Now try lifted version of predefined operator
4451 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4452 if (nullable_type != null) {
4453 if (renum && !ltype.IsNullableType) {
4454 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4456 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4459 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4462 if ((oper & Operator.BitwiseMask) != 0)
4466 if ((oper & Operator.BitwiseMask) != 0)
4467 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4469 return CreateLiftedValueTypeResult (rc, rtype);
4473 var lifted = new Nullable.LiftedBinaryOperator (this);
4475 lifted.Right = right;
4476 return lifted.Resolve (rc);
4478 } else if (lenum && !rtype.IsNullableType) {
4479 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4481 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4484 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4487 if ((oper & Operator.BitwiseMask) != 0)
4491 if ((oper & Operator.BitwiseMask) != 0)
4492 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4494 return CreateLiftedValueTypeResult (rc, ltype);
4498 var lifted = new Nullable.LiftedBinaryOperator (this);
4500 lifted.Right = expr;
4501 return lifted.Resolve (rc);
4503 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4504 Nullable.Unwrap unwrap = null;
4505 if (left.IsNull || right.IsNull) {
4506 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4507 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4509 if ((oper & Operator.RelationalMask) != 0)
4510 return CreateLiftedValueTypeResult (rc, rtype);
4512 if ((oper & Operator.BitwiseMask) != 0)
4513 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4516 return CreateLiftedValueTypeResult (rc, left.Type);
4518 // Equality operators are valid between E? and null
4520 unwrap = new Nullable.Unwrap (right);
4522 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4526 if ((oper & Operator.BitwiseMask) != 0)
4531 var lifted = new Nullable.LiftedBinaryOperator (this);
4533 lifted.Right = right;
4534 lifted.UnwrapRight = unwrap;
4535 return lifted.Resolve (rc);
4537 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4538 Nullable.Unwrap unwrap = null;
4539 if (right.IsNull || left.IsNull) {
4540 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4541 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4543 if ((oper & Operator.RelationalMask) != 0)
4544 return CreateLiftedValueTypeResult (rc, ltype);
4546 if ((oper & Operator.BitwiseMask) != 0)
4547 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4550 return CreateLiftedValueTypeResult (rc, right.Type);
4552 // Equality operators are valid between E? and null
4554 unwrap = new Nullable.Unwrap (left);
4556 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4560 if ((oper & Operator.BitwiseMask) != 0)
4565 var lifted = new Nullable.LiftedBinaryOperator (this);
4567 lifted.UnwrapLeft = unwrap;
4568 lifted.Right = expr;
4569 return lifted.Resolve (rc);
4577 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4579 TypeSpec underlying_type;
4580 if (expr.Type.IsNullableType) {
4581 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4583 underlying_type = EnumSpec.GetUnderlyingType (nt);
4585 underlying_type = nt;
4586 } else if (expr.Type.IsEnum) {
4587 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4589 underlying_type = expr.Type;
4592 switch (underlying_type.BuiltinType) {
4593 case BuiltinTypeSpec.Type.SByte:
4594 case BuiltinTypeSpec.Type.Byte:
4595 case BuiltinTypeSpec.Type.Short:
4596 case BuiltinTypeSpec.Type.UShort:
4597 underlying_type = rc.BuiltinTypes.Int;
4601 if (expr.Type.IsNullableType || liftType)
4602 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4604 if (expr.Type == underlying_type)
4607 return EmptyCast.Create (expr, underlying_type);
4610 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4613 // U operator - (E e, E f)
4614 // E operator - (E e, U x) // Internal decomposition operator
4615 // E operator - (U x, E e) // Internal decomposition operator
4617 // E operator + (E e, U x)
4618 // E operator + (U x, E e)
4627 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4633 if (!enum_type.IsNullableType) {
4634 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4636 if (oper == Operator.Subtraction)
4637 expr = ConvertEnumSubtractionResult (rc, expr);
4639 expr = ConvertEnumAdditionalResult (expr, enum_type);
4641 enum_conversion = GetEnumResultCast (expr.Type);
4646 var nullable = rc.Module.PredefinedTypes.Nullable;
4649 // Don't try nullable version when nullable type is undefined
4651 if (!nullable.IsDefined)
4654 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4657 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4659 if (oper == Operator.Subtraction)
4660 expr = ConvertEnumSubtractionResult (rc, expr);
4662 expr = ConvertEnumAdditionalResult (expr, enum_type);
4664 enum_conversion = GetEnumResultCast (expr.Type);
4670 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4672 return EmptyCast.Create (expr, enumType);
4675 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4678 // Enumeration subtraction has different result type based on
4681 TypeSpec result_type;
4682 if (left.Type == right.Type) {
4683 var c = right as EnumConstant;
4684 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4686 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4687 // E which is not what expressions E - 1 or 0 - E return
4689 result_type = left.Type;
4691 result_type = left.Type.IsNullableType ?
4692 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4693 EnumSpec.GetUnderlyingType (left.Type);
4696 if (IsEnumOrNullableEnum (left.Type)) {
4697 result_type = left.Type;
4699 result_type = right.Type;
4702 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4703 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4706 return EmptyCast.Create (expr, result_type);
4709 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4711 if (type.IsNullableType)
4712 type = Nullable.NullableInfo.GetUnderlyingType (type);
4715 type = EnumSpec.GetUnderlyingType (type);
4717 switch (type.BuiltinType) {
4718 case BuiltinTypeSpec.Type.SByte:
4719 return ConvCast.Mode.I4_I1;
4720 case BuiltinTypeSpec.Type.Byte:
4721 return ConvCast.Mode.I4_U1;
4722 case BuiltinTypeSpec.Type.Short:
4723 return ConvCast.Mode.I4_I2;
4724 case BuiltinTypeSpec.Type.UShort:
4725 return ConvCast.Mode.I4_U2;
4732 // Equality operators rules
4734 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4737 type = ec.BuiltinTypes.Bool;
4738 bool no_arg_conv = false;
4740 if (!primitives_only) {
4743 // a, Both operands are reference-type values or the value null
4744 // b, One operand is a value of type T where T is a type-parameter and
4745 // the other operand is the value null. Furthermore T does not have the
4746 // value type constraint
4748 // LAMESPEC: Very confusing details in the specification, basically any
4749 // reference like type-parameter is allowed
4751 var tparam_l = l as TypeParameterSpec;
4752 var tparam_r = r as TypeParameterSpec;
4753 if (tparam_l != null) {
4754 if (right is NullLiteral) {
4755 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4758 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4762 if (!tparam_l.IsReferenceType)
4765 l = tparam_l.GetEffectiveBase ();
4766 left = new BoxedCast (left, l);
4767 } else if (left is NullLiteral && tparam_r == null) {
4768 if (TypeSpec.IsReferenceType (r))
4771 if (r.Kind == MemberKind.InternalCompilerType)
4775 if (tparam_r != null) {
4776 if (left is NullLiteral) {
4777 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4780 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4784 if (!tparam_r.IsReferenceType)
4787 r = tparam_r.GetEffectiveBase ();
4788 right = new BoxedCast (right, r);
4789 } else if (right is NullLiteral) {
4790 if (TypeSpec.IsReferenceType (l))
4793 if (l.Kind == MemberKind.InternalCompilerType)
4798 // LAMESPEC: method groups can be compared when they convert to other side delegate
4801 if (right.eclass == ExprClass.MethodGroup) {
4802 result = Convert.ImplicitConversion (ec, right, l, loc);
4808 } else if (r.IsDelegate && l != r) {
4811 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4812 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4819 no_arg_conv = l == r && !l.IsStruct;
4824 // bool operator != (string a, string b)
4825 // bool operator == (string a, string b)
4827 // bool operator != (Delegate a, Delegate b)
4828 // bool operator == (Delegate a, Delegate b)
4830 // bool operator != (bool a, bool b)
4831 // bool operator == (bool a, bool b)
4833 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4834 // they implement an implicit conversion to any of types above. This does
4835 // not apply when both operands are of same reference type
4837 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4838 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4843 // Now try lifted version of predefined operators
4845 if (no_arg_conv && !l.IsNullableType) {
4847 // Optimizes cases which won't match
4850 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4856 // The == and != operators permit one operand to be a value of a nullable
4857 // type and the other to be the null literal, even if no predefined or user-defined
4858 // operator (in unlifted or lifted form) exists for the operation.
4860 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4861 var lifted = new Nullable.LiftedBinaryOperator (this);
4863 lifted.Right = right;
4864 return lifted.Resolve (ec);
4869 // bool operator != (object a, object b)
4870 // bool operator == (object a, object b)
4872 // An explicit reference conversion exists from the
4873 // type of either operand to the type of the other operand.
4876 // Optimize common path
4878 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4881 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4882 !Convert.ExplicitReferenceConversionExists (r, l))
4885 // Reject allowed explicit conversions like int->object
4886 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4889 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4890 ec.Report.Warning (253, 2, loc,
4891 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4892 l.GetSignatureForError ());
4894 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4895 ec.Report.Warning (252, 2, loc,
4896 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4897 r.GetSignatureForError ());
4903 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4906 // bool operator == (void* x, void* y);
4907 // bool operator != (void* x, void* y);
4908 // bool operator < (void* x, void* y);
4909 // bool operator > (void* x, void* y);
4910 // bool operator <= (void* x, void* y);
4911 // bool operator >= (void* x, void* y);
4913 if ((oper & Operator.ComparisonMask) != 0) {
4916 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4923 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4929 type = ec.BuiltinTypes.Bool;
4933 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4937 // Build-in operators method overloading
4939 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4941 PredefinedOperator best_operator = null;
4942 TypeSpec l = left.Type;
4943 TypeSpec r = right.Type;
4944 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4946 foreach (PredefinedOperator po in operators) {
4947 if ((po.OperatorsMask & oper_mask) == 0)
4950 if (primitives_only) {
4951 if (!po.IsPrimitiveApplicable (l, r))
4954 if (!po.IsApplicable (ec, left, right))
4958 if (best_operator == null) {
4960 if (primitives_only)
4966 best_operator = po.ResolveBetterOperator (ec, best_operator);
4968 if (best_operator == null) {
4969 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4970 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4977 if (best_operator == null)
4980 return best_operator.ConvertResult (ec, this);
4984 // Optimize & constant expressions with 0 value
4986 Expression OptimizeAndOperation (Expression expr)
4988 Constant rc = right as Constant;
4989 Constant lc = left as Constant;
4990 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4992 // The result is a constant with side-effect
4994 Constant side_effect = rc == null ?
4995 new SideEffectConstant (lc, right, loc) :
4996 new SideEffectConstant (rc, left, loc);
4998 return ReducedExpression.Create (side_effect, expr);
5005 // Value types can be compared with the null literal because of the lifting
5006 // language rules. However the result is always true or false.
5008 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5010 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5011 type = rc.BuiltinTypes.Bool;
5015 // FIXME: Handle side effect constants
5016 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5018 if ((Oper & Operator.EqualityMask) != 0) {
5019 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5020 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5022 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5023 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5030 // Performs user-operator overloading
5032 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5034 Expression oper_expr;
5036 var op = ConvertBinaryToUserOperator (oper);
5038 if (l.IsNullableType)
5039 l = Nullable.NullableInfo.GetUnderlyingType (l);
5041 if (r.IsNullableType)
5042 r = Nullable.NullableInfo.GetUnderlyingType (r);
5044 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5045 IList<MemberSpec> right_operators = null;
5048 right_operators = MemberCache.GetUserOperator (r, op, false);
5049 if (right_operators == null && left_operators == null)
5051 } else if (left_operators == null) {
5055 Arguments args = new Arguments (2);
5056 Argument larg = new Argument (left);
5058 Argument rarg = new Argument (right);
5062 // User-defined operator implementations always take precedence
5063 // over predefined operator implementations
5065 if (left_operators != null && right_operators != null) {
5066 left_operators = CombineUserOperators (left_operators, right_operators);
5067 } else if (right_operators != null) {
5068 left_operators = right_operators;
5071 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5072 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5074 var res = new OverloadResolver (left_operators, restr, loc);
5076 var oper_method = res.ResolveOperator (rc, ref args);
5077 if (oper_method == null) {
5079 // Logical && and || cannot be lifted
5081 if ((oper & Operator.LogicalMask) != 0)
5085 // Apply lifted user operators only for liftable types. Implicit conversion
5086 // to nullable types is not allowed
5088 if (!IsLiftedOperatorApplicable ())
5091 // TODO: Cache the result in module container
5092 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5093 if (lifted_methods == null)
5096 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5098 oper_method = res.ResolveOperator (rc, ref args);
5099 if (oper_method == null)
5102 MethodSpec best_original = null;
5103 foreach (MethodSpec ms in left_operators) {
5104 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5110 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5112 // Expression trees use lifted notation in this case
5114 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5115 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5118 var ptypes = best_original.Parameters.Types;
5120 if (left.IsNull || right.IsNull) {
5122 // The lifted operator produces a null value if one or both operands are null
5124 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5125 type = oper_method.ReturnType;
5126 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5130 // The lifted operator produces the value false if one or both operands are null for
5131 // relational operators.
5133 if ((oper & Operator.RelationalMask) != 0) {
5135 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5136 // because return type is actually bool
5138 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5141 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5142 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5146 type = oper_method.ReturnType;
5147 var lifted = new Nullable.LiftedBinaryOperator (this);
5148 lifted.UserOperator = best_original;
5150 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5151 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5154 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5155 lifted.UnwrapRight = new Nullable.Unwrap (right);
5158 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5159 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5161 return lifted.Resolve (rc);
5164 if ((oper & Operator.LogicalMask) != 0) {
5165 // TODO: CreateExpressionTree is allocated every time
5166 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5167 oper == Operator.LogicalAnd, loc).Resolve (rc);
5169 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5172 this.left = larg.Expr;
5173 this.right = rarg.Expr;
5178 bool IsLiftedOperatorApplicable ()
5180 if (left.Type.IsNullableType) {
5181 if ((oper & Operator.EqualityMask) != 0)
5182 return !right.IsNull;
5187 if (right.Type.IsNullableType) {
5188 if ((oper & Operator.EqualityMask) != 0)
5189 return !left.IsNull;
5194 if (TypeSpec.IsValueType (left.Type))
5195 return right.IsNull;
5197 if (TypeSpec.IsValueType (right.Type))
5203 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5205 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5206 if (nullable_type == null)
5210 // Lifted operators permit predefined and user-defined operators that operate
5211 // on non-nullable value types to also be used with nullable forms of those types.
5212 // Lifted operators are constructed from predefined and user-defined operators
5213 // that meet certain requirements
5215 List<MemberSpec> lifted = null;
5216 foreach (MethodSpec oper in operators) {
5218 if ((Oper & Operator.ComparisonMask) != 0) {
5220 // Result type must be of type bool for lifted comparison operators
5222 rt = oper.ReturnType;
5223 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5226 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5232 var ptypes = oper.Parameters.Types;
5233 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5237 // LAMESPEC: I am not sure why but for equality operators to be lifted
5238 // both types have to match
5240 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5244 lifted = new List<MemberSpec> ();
5247 // The lifted form is constructed by adding a single ? modifier to each operand and
5248 // result type except for comparison operators where return type is bool
5251 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5253 var parameters = ParametersCompiled.CreateFullyResolved (
5254 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5255 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5257 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5258 rt, parameters, oper.Modifiers);
5260 lifted.Add (lifted_op);
5267 // Merge two sets of user operators into one, they are mostly distinguish
5268 // except when they share base type and it contains an operator
5270 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5272 var combined = new List<MemberSpec> (left.Count + right.Count);
5273 combined.AddRange (left);
5274 foreach (var r in right) {
5276 foreach (var l in left) {
5277 if (l.DeclaringType == r.DeclaringType) {
5290 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5292 if (c is IntegralConstant || c is CharConstant) {
5294 c.ConvertExplicitly (true, type);
5295 } catch (OverflowException) {
5296 ec.Report.Warning (652, 2, loc,
5297 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5298 type.GetSignatureForError ());
5304 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5305 /// context of a conditional bool expression. This function will return
5306 /// false if it is was possible to use EmitBranchable, or true if it was.
5308 /// The expression's code is generated, and we will generate a branch to `target'
5309 /// if the resulting expression value is equal to isTrue
5311 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5313 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5314 left = left.EmitToField (ec);
5316 if ((oper & Operator.LogicalMask) == 0) {
5317 right = right.EmitToField (ec);
5322 // This is more complicated than it looks, but its just to avoid
5323 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5324 // but on top of that we want for == and != to use a special path
5325 // if we are comparing against null
5327 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5328 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5331 // put the constant on the rhs, for simplicity
5333 if (left is Constant) {
5334 Expression swap = right;
5340 // brtrue/brfalse works with native int only
5342 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5343 left.EmitBranchable (ec, target, my_on_true);
5346 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5347 // right is a boolean, and it's not 'false' => it is 'true'
5348 left.EmitBranchable (ec, target, !my_on_true);
5352 } else if (oper == Operator.LogicalAnd) {
5355 Label tests_end = ec.DefineLabel ();
5357 left.EmitBranchable (ec, tests_end, false);
5358 right.EmitBranchable (ec, target, true);
5359 ec.MarkLabel (tests_end);
5362 // This optimizes code like this
5363 // if (true && i > 4)
5365 if (!(left is Constant))
5366 left.EmitBranchable (ec, target, false);
5368 if (!(right is Constant))
5369 right.EmitBranchable (ec, target, false);
5374 } else if (oper == Operator.LogicalOr){
5376 left.EmitBranchable (ec, target, true);
5377 right.EmitBranchable (ec, target, true);
5380 Label tests_end = ec.DefineLabel ();
5381 left.EmitBranchable (ec, tests_end, true);
5382 right.EmitBranchable (ec, target, false);
5383 ec.MarkLabel (tests_end);
5388 } else if ((oper & Operator.ComparisonMask) == 0) {
5389 base.EmitBranchable (ec, target, on_true);
5396 TypeSpec t = left.Type;
5397 bool is_float = IsFloat (t);
5398 bool is_unsigned = is_float || IsUnsigned (t);
5401 case Operator.Equality:
5403 ec.Emit (OpCodes.Beq, target);
5405 ec.Emit (OpCodes.Bne_Un, target);
5408 case Operator.Inequality:
5410 ec.Emit (OpCodes.Bne_Un, target);
5412 ec.Emit (OpCodes.Beq, target);
5415 case Operator.LessThan:
5417 if (is_unsigned && !is_float)
5418 ec.Emit (OpCodes.Blt_Un, target);
5420 ec.Emit (OpCodes.Blt, target);
5423 ec.Emit (OpCodes.Bge_Un, target);
5425 ec.Emit (OpCodes.Bge, target);
5428 case Operator.GreaterThan:
5430 if (is_unsigned && !is_float)
5431 ec.Emit (OpCodes.Bgt_Un, target);
5433 ec.Emit (OpCodes.Bgt, target);
5436 ec.Emit (OpCodes.Ble_Un, target);
5438 ec.Emit (OpCodes.Ble, target);
5441 case Operator.LessThanOrEqual:
5443 if (is_unsigned && !is_float)
5444 ec.Emit (OpCodes.Ble_Un, target);
5446 ec.Emit (OpCodes.Ble, target);
5449 ec.Emit (OpCodes.Bgt_Un, target);
5451 ec.Emit (OpCodes.Bgt, target);
5455 case Operator.GreaterThanOrEqual:
5457 if (is_unsigned && !is_float)
5458 ec.Emit (OpCodes.Bge_Un, target);
5460 ec.Emit (OpCodes.Bge, target);
5463 ec.Emit (OpCodes.Blt_Un, target);
5465 ec.Emit (OpCodes.Blt, target);
5468 throw new InternalErrorException (oper.ToString ());
5472 public override void Emit (EmitContext ec)
5474 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5475 left = left.EmitToField (ec);
5477 if ((oper & Operator.LogicalMask) == 0) {
5478 right = right.EmitToField (ec);
5483 // Handle short-circuit operators differently
5486 if ((oper & Operator.LogicalMask) != 0) {
5487 Label load_result = ec.DefineLabel ();
5488 Label end = ec.DefineLabel ();
5490 bool is_or = oper == Operator.LogicalOr;
5491 left.EmitBranchable (ec, load_result, is_or);
5493 ec.Emit (OpCodes.Br_S, end);
5495 ec.MarkLabel (load_result);
5496 ec.EmitInt (is_or ? 1 : 0);
5502 // Optimize zero-based operations which cannot be optimized at expression level
5504 if (oper == Operator.Subtraction) {
5505 var lc = left as IntegralConstant;
5506 if (lc != null && lc.IsDefaultValue) {
5508 ec.Emit (OpCodes.Neg);
5513 EmitOperator (ec, left, right);
5516 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5521 EmitOperatorOpcode (ec, oper, left.Type, right);
5524 // Emit result enumerable conversion this way because it's quite complicated get it
5525 // to resolved tree because expression tree cannot see it.
5527 if (enum_conversion != 0)
5528 ConvCast.Emit (ec, enum_conversion);
5531 public override void EmitSideEffect (EmitContext ec)
5533 if ((oper & Operator.LogicalMask) != 0 ||
5534 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5535 base.EmitSideEffect (ec);
5537 left.EmitSideEffect (ec);
5538 right.EmitSideEffect (ec);
5542 public override Expression EmitToField (EmitContext ec)
5544 if ((oper & Operator.LogicalMask) == 0) {
5545 var await_expr = left as Await;
5546 if (await_expr != null && right.IsSideEffectFree) {
5547 await_expr.Statement.EmitPrologue (ec);
5548 left = await_expr.Statement.GetResultExpression (ec);
5552 await_expr = right as Await;
5553 if (await_expr != null && left.IsSideEffectFree) {
5554 await_expr.Statement.EmitPrologue (ec);
5555 right = await_expr.Statement.GetResultExpression (ec);
5560 return base.EmitToField (ec);
5563 protected override void CloneTo (CloneContext clonectx, Expression t)
5565 Binary target = (Binary) t;
5567 target.left = left.Clone (clonectx);
5568 target.right = right.Clone (clonectx);
5571 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5573 Arguments binder_args = new Arguments (4);
5575 MemberAccess sle = new MemberAccess (new MemberAccess (
5576 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5578 CSharpBinderFlags flags = 0;
5579 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5580 flags = CSharpBinderFlags.CheckedContext;
5582 if ((oper & Operator.LogicalMask) != 0)
5583 flags |= CSharpBinderFlags.BinaryOperationLogical;
5585 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5586 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5587 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5588 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5590 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5593 public override Expression CreateExpressionTree (ResolveContext ec)
5595 return CreateExpressionTree (ec, null);
5598 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5601 bool lift_arg = false;
5604 case Operator.Addition:
5605 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5606 method_name = "AddChecked";
5608 method_name = "Add";
5610 case Operator.BitwiseAnd:
5611 method_name = "And";
5613 case Operator.BitwiseOr:
5616 case Operator.Division:
5617 method_name = "Divide";
5619 case Operator.Equality:
5620 method_name = "Equal";
5623 case Operator.ExclusiveOr:
5624 method_name = "ExclusiveOr";
5626 case Operator.GreaterThan:
5627 method_name = "GreaterThan";
5630 case Operator.GreaterThanOrEqual:
5631 method_name = "GreaterThanOrEqual";
5634 case Operator.Inequality:
5635 method_name = "NotEqual";
5638 case Operator.LeftShift:
5639 method_name = "LeftShift";
5641 case Operator.LessThan:
5642 method_name = "LessThan";
5645 case Operator.LessThanOrEqual:
5646 method_name = "LessThanOrEqual";
5649 case Operator.LogicalAnd:
5650 method_name = "AndAlso";
5652 case Operator.LogicalOr:
5653 method_name = "OrElse";
5655 case Operator.Modulus:
5656 method_name = "Modulo";
5658 case Operator.Multiply:
5659 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5660 method_name = "MultiplyChecked";
5662 method_name = "Multiply";
5664 case Operator.RightShift:
5665 method_name = "RightShift";
5667 case Operator.Subtraction:
5668 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5669 method_name = "SubtractChecked";
5671 method_name = "Subtract";
5675 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5678 Arguments args = new Arguments (2);
5679 args.Add (new Argument (left.CreateExpressionTree (ec)));
5680 args.Add (new Argument (right.CreateExpressionTree (ec)));
5681 if (method != null) {
5683 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5685 args.Add (new Argument (method));
5688 return CreateExpressionFactoryCall (ec, method_name, args);
5691 public override object Accept (StructuralVisitor visitor)
5693 return visitor.Visit (this);
5699 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5700 // b, c, d... may be strings or objects.
5702 public class StringConcat : Expression
5704 Arguments arguments;
5706 StringConcat (Location loc)
5709 arguments = new Arguments (2);
5712 public override bool ContainsEmitWithAwait ()
5714 return arguments.ContainsEmitWithAwait ();
5717 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5719 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5720 throw new ArgumentException ();
5722 var s = new StringConcat (loc);
5723 s.type = rc.BuiltinTypes.String;
5724 s.eclass = ExprClass.Value;
5726 s.Append (rc, left);
5727 s.Append (rc, right);
5731 public override Expression CreateExpressionTree (ResolveContext ec)
5733 Argument arg = arguments [0];
5734 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5738 // Creates nested calls tree from an array of arguments used for IL emit
5740 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5742 Arguments concat_args = new Arguments (2);
5743 Arguments add_args = new Arguments (3);
5745 concat_args.Add (left);
5746 add_args.Add (new Argument (left_etree));
5748 concat_args.Add (arguments [pos]);
5749 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5751 var methods = GetConcatMethodCandidates ();
5752 if (methods == null)
5755 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5756 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5760 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5762 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5763 if (++pos == arguments.Count)
5766 left = new Argument (new EmptyExpression (method.ReturnType));
5767 return CreateExpressionAddCall (ec, left, expr, pos);
5770 protected override Expression DoResolve (ResolveContext ec)
5775 void Append (ResolveContext rc, Expression operand)
5780 StringConstant sc = operand as StringConstant;
5782 if (arguments.Count != 0) {
5783 Argument last_argument = arguments [arguments.Count - 1];
5784 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5785 if (last_expr_constant != null) {
5786 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5792 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5794 StringConcat concat_oper = operand as StringConcat;
5795 if (concat_oper != null) {
5796 arguments.AddRange (concat_oper.arguments);
5801 arguments.Add (new Argument (operand));
5804 IList<MemberSpec> GetConcatMethodCandidates ()
5806 return MemberCache.FindMembers (type, "Concat", true);
5809 public override void Emit (EmitContext ec)
5811 // Optimize by removing any extra null arguments, they are no-op
5812 for (int i = 0; i < arguments.Count; ++i) {
5813 if (arguments[i].Expr is NullConstant)
5814 arguments.RemoveAt (i--);
5817 var members = GetConcatMethodCandidates ();
5818 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5819 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5820 if (method != null) {
5821 var call = new CallEmitter ();
5822 call.EmitPredefined (ec, method, arguments, false);
5826 public override void FlowAnalysis (FlowAnalysisContext fc)
5828 arguments.FlowAnalysis (fc);
5831 public override SLE.Expression MakeExpression (BuilderContext ctx)
5833 if (arguments.Count != 2)
5834 throw new NotImplementedException ("arguments.Count != 2");
5836 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5837 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5842 // User-defined conditional logical operator
5844 public class ConditionalLogicalOperator : UserOperatorCall
5846 readonly bool is_and;
5847 Expression oper_expr;
5849 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5850 : base (oper, arguments, expr_tree, loc)
5852 this.is_and = is_and;
5853 eclass = ExprClass.Unresolved;
5856 protected override Expression DoResolve (ResolveContext ec)
5858 AParametersCollection pd = oper.Parameters;
5859 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5860 ec.Report.Error (217, loc,
5861 "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",
5862 oper.GetSignatureForError ());
5866 Expression left_dup = new EmptyExpression (type);
5867 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5868 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5869 if (op_true == null || op_false == null) {
5870 ec.Report.Error (218, loc,
5871 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5872 type.GetSignatureForError (), oper.GetSignatureForError ());
5876 oper_expr = is_and ? op_false : op_true;
5877 eclass = ExprClass.Value;
5881 public override void Emit (EmitContext ec)
5883 Label end_target = ec.DefineLabel ();
5886 // Emit and duplicate left argument
5888 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5889 if (right_contains_await) {
5890 arguments[0] = arguments[0].EmitToField (ec, false);
5891 arguments[0].Expr.Emit (ec);
5893 arguments[0].Expr.Emit (ec);
5894 ec.Emit (OpCodes.Dup);
5895 arguments.RemoveAt (0);
5898 oper_expr.EmitBranchable (ec, end_target, true);
5902 if (right_contains_await) {
5904 // Special handling when right expression contains await and left argument
5905 // could not be left on stack before logical branch
5907 Label skip_left_load = ec.DefineLabel ();
5908 ec.Emit (OpCodes.Br_S, skip_left_load);
5909 ec.MarkLabel (end_target);
5910 arguments[0].Expr.Emit (ec);
5911 ec.MarkLabel (skip_left_load);
5913 ec.MarkLabel (end_target);
5918 public class PointerArithmetic : Expression {
5919 Expression left, right;
5920 readonly Binary.Operator op;
5923 // We assume that `l' is always a pointer
5925 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5934 public override bool ContainsEmitWithAwait ()
5936 throw new NotImplementedException ();
5939 public override Expression CreateExpressionTree (ResolveContext ec)
5941 Error_PointerInsideExpressionTree (ec);
5945 protected override Expression DoResolve (ResolveContext ec)
5947 eclass = ExprClass.Variable;
5949 var pc = left.Type as PointerContainer;
5950 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5951 Error_VoidPointerOperation (ec);
5958 public override void Emit (EmitContext ec)
5960 TypeSpec op_type = left.Type;
5962 // It must be either array or fixed buffer
5964 if (TypeManager.HasElementType (op_type)) {
5965 element = TypeManager.GetElementType (op_type);
5967 FieldExpr fe = left as FieldExpr;
5969 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5974 int size = BuiltinTypeSpec.GetSize(element);
5975 TypeSpec rtype = right.Type;
5977 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5979 // handle (pointer - pointer)
5983 ec.Emit (OpCodes.Sub);
5987 ec.Emit (OpCodes.Sizeof, element);
5990 ec.Emit (OpCodes.Div);
5992 ec.Emit (OpCodes.Conv_I8);
5995 // handle + and - on (pointer op int)
5997 Constant left_const = left as Constant;
5998 if (left_const != null) {
6000 // Optimize ((T*)null) pointer operations
6002 if (left_const.IsDefaultValue) {
6003 left = EmptyExpression.Null;
6011 var right_const = right as Constant;
6012 if (right_const != null) {
6014 // Optimize 0-based arithmetic
6016 if (right_const.IsDefaultValue)
6020 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6022 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6024 // TODO: Should be the checks resolve context sensitive?
6025 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6026 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6032 if (right_const == null) {
6033 switch (rtype.BuiltinType) {
6034 case BuiltinTypeSpec.Type.SByte:
6035 case BuiltinTypeSpec.Type.Byte:
6036 case BuiltinTypeSpec.Type.Short:
6037 case BuiltinTypeSpec.Type.UShort:
6038 case BuiltinTypeSpec.Type.Int:
6039 ec.Emit (OpCodes.Conv_I);
6041 case BuiltinTypeSpec.Type.UInt:
6042 ec.Emit (OpCodes.Conv_U);
6047 if (right_const == null && size != 1){
6049 ec.Emit (OpCodes.Sizeof, element);
6052 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6053 ec.Emit (OpCodes.Conv_I8);
6055 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6058 if (left_const == null) {
6059 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6060 ec.Emit (OpCodes.Conv_I);
6061 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6062 ec.Emit (OpCodes.Conv_U);
6064 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6071 // A boolean-expression is an expression that yields a result
6074 public class BooleanExpression : ShimExpression
6076 public BooleanExpression (Expression expr)
6079 this.loc = expr.Location;
6082 public override Expression CreateExpressionTree (ResolveContext ec)
6084 // TODO: We should emit IsTrue (v4) instead of direct user operator
6085 // call but that would break csc compatibility
6086 return base.CreateExpressionTree (ec);
6089 protected override Expression DoResolve (ResolveContext ec)
6091 // A boolean-expression is required to be of a type
6092 // that can be implicitly converted to bool or of
6093 // a type that implements operator true
6095 expr = expr.Resolve (ec);
6099 Assign ass = expr as Assign;
6100 if (ass != null && ass.Source is Constant) {
6101 ec.Report.Warning (665, 3, loc,
6102 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6105 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6108 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6109 Arguments args = new Arguments (1);
6110 args.Add (new Argument (expr));
6111 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6114 type = ec.BuiltinTypes.Bool;
6115 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6116 if (converted != null)
6120 // If no implicit conversion to bool exists, try using `operator true'
6122 converted = GetOperatorTrue (ec, expr, loc);
6123 if (converted == null) {
6124 expr.Error_ValueCannotBeConverted (ec, type, false);
6131 public override object Accept (StructuralVisitor visitor)
6133 return visitor.Visit (this);
6137 public class BooleanExpressionFalse : Unary
6139 public BooleanExpressionFalse (Expression expr)
6140 : base (Operator.LogicalNot, expr, expr.Location)
6144 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6146 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6151 /// Implements the ternary conditional operator (?:)
6153 public class Conditional : Expression {
6154 Expression expr, true_expr, false_expr;
6156 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6159 this.true_expr = true_expr;
6160 this.false_expr = false_expr;
6166 public Expression Expr {
6172 public Expression TrueExpr {
6178 public Expression FalseExpr {
6186 public override bool ContainsEmitWithAwait ()
6188 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6191 public override Expression CreateExpressionTree (ResolveContext ec)
6193 Arguments args = new Arguments (3);
6194 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6195 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6196 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6197 return CreateExpressionFactoryCall (ec, "Condition", args);
6200 protected override Expression DoResolve (ResolveContext ec)
6202 expr = expr.Resolve (ec);
6203 true_expr = true_expr.Resolve (ec);
6204 false_expr = false_expr.Resolve (ec);
6206 if (true_expr == null || false_expr == null || expr == null)
6209 eclass = ExprClass.Value;
6210 TypeSpec true_type = true_expr.Type;
6211 TypeSpec false_type = false_expr.Type;
6215 // First, if an implicit conversion exists from true_expr
6216 // to false_expr, then the result type is of type false_expr.Type
6218 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6219 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6220 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6222 // Check if both can convert implicitly to each other's type
6226 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6227 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6229 // LAMESPEC: There seems to be hardcoded promotition to int type when
6230 // both sides are numeric constants and one side is int constant and
6231 // other side is numeric constant convertible to int.
6233 // var res = condition ? (short)1 : 1;
6235 // Type of res is int even if according to the spec the conversion is
6236 // ambiguous because 1 literal can be converted to short.
6238 if (conv_false_expr != null) {
6239 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6241 conv_false_expr = null;
6242 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6243 conv_false_expr = null;
6247 if (conv_false_expr != null) {
6248 ec.Report.Error (172, true_expr.Location,
6249 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6250 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6255 if (true_expr.Type != type)
6256 true_expr = EmptyCast.Create (true_expr, type);
6257 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6260 if (false_type != InternalType.ErrorType) {
6261 ec.Report.Error (173, true_expr.Location,
6262 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6263 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6269 Constant c = expr as Constant;
6271 bool is_false = c.IsDefaultValue;
6274 // Don't issue the warning for constant expressions
6276 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6277 // CSC: Missing warning
6278 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6281 return ReducedExpression.Create (
6282 is_false ? false_expr : true_expr, this,
6283 false_expr is Constant && true_expr is Constant).Resolve (ec);
6289 public override void Emit (EmitContext ec)
6291 Label false_target = ec.DefineLabel ();
6292 Label end_target = ec.DefineLabel ();
6294 expr.EmitBranchable (ec, false_target, false);
6295 true_expr.Emit (ec);
6298 // Verifier doesn't support interface merging. When there are two types on
6299 // the stack without common type hint and the common type is an interface.
6300 // Use temporary local to give verifier hint on what type to unify the stack
6302 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6303 var temp = ec.GetTemporaryLocal (type);
6304 ec.Emit (OpCodes.Stloc, temp);
6305 ec.Emit (OpCodes.Ldloc, temp);
6306 ec.FreeTemporaryLocal (temp, type);
6309 ec.Emit (OpCodes.Br, end_target);
6310 ec.MarkLabel (false_target);
6311 false_expr.Emit (ec);
6312 ec.MarkLabel (end_target);
6315 public override void FlowAnalysis (FlowAnalysisContext fc)
6317 expr.FlowAnalysisConditional (fc);
6318 var expr_true = fc.DefiniteAssignmentOnTrue;
6319 var expr_false = fc.DefiniteAssignmentOnFalse;
6321 fc.BranchDefiniteAssignment (expr_true);
6322 true_expr.FlowAnalysis (fc);
6323 var true_fc = fc.DefiniteAssignment;
6325 fc.BranchDefiniteAssignment (expr_false);
6326 false_expr.FlowAnalysis (fc);
6328 fc.DefiniteAssignment &= true_fc;
6331 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6333 expr.FlowAnalysisConditional (fc);
6334 var expr_true = fc.DefiniteAssignmentOnTrue;
6335 var expr_false = fc.DefiniteAssignmentOnFalse;
6337 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6338 true_expr.FlowAnalysisConditional (fc);
6339 var true_fc = fc.DefiniteAssignment;
6340 var true_da_true = fc.DefiniteAssignmentOnTrue;
6341 var true_da_false = fc.DefiniteAssignmentOnFalse;
6343 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6344 false_expr.FlowAnalysisConditional (fc);
6346 fc.DefiniteAssignment &= true_fc;
6347 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6348 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6351 protected override void CloneTo (CloneContext clonectx, Expression t)
6353 Conditional target = (Conditional) t;
6355 target.expr = expr.Clone (clonectx);
6356 target.true_expr = true_expr.Clone (clonectx);
6357 target.false_expr = false_expr.Clone (clonectx);
6361 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6363 LocalTemporary temp;
6366 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6367 public abstract void SetHasAddressTaken ();
6369 public abstract bool IsLockedByStatement { get; set; }
6371 public abstract bool IsFixed { get; }
6372 public abstract bool IsRef { get; }
6373 public abstract string Name { get; }
6376 // Variable IL data, it has to be protected to encapsulate hoisted variables
6378 protected abstract ILocalVariable Variable { get; }
6381 // Variable flow-analysis data
6383 public abstract VariableInfo VariableInfo { get; }
6386 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6388 HoistedVariable hv = GetHoistedVariable (ec);
6390 hv.AddressOf (ec, mode);
6394 Variable.EmitAddressOf (ec);
6397 public override bool ContainsEmitWithAwait ()
6402 public override Expression CreateExpressionTree (ResolveContext ec)
6404 HoistedVariable hv = GetHoistedVariable (ec);
6406 return hv.CreateExpressionTree ();
6408 Arguments arg = new Arguments (1);
6409 arg.Add (new Argument (this));
6410 return CreateExpressionFactoryCall (ec, "Constant", arg);
6413 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6415 if (IsLockedByStatement) {
6416 rc.Report.Warning (728, 2, loc,
6417 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6424 public override void Emit (EmitContext ec)
6429 public override void EmitSideEffect (EmitContext ec)
6435 // This method is used by parameters that are references, that are
6436 // being passed as references: we only want to pass the pointer (that
6437 // is already stored in the parameter, not the address of the pointer,
6438 // and not the value of the variable).
6440 public void EmitLoad (EmitContext ec)
6445 public void Emit (EmitContext ec, bool leave_copy)
6447 HoistedVariable hv = GetHoistedVariable (ec);
6449 hv.Emit (ec, leave_copy);
6457 // If we are a reference, we loaded on the stack a pointer
6458 // Now lets load the real value
6460 ec.EmitLoadFromPtr (type);
6464 ec.Emit (OpCodes.Dup);
6467 temp = new LocalTemporary (Type);
6473 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6474 bool prepare_for_load)
6476 HoistedVariable hv = GetHoistedVariable (ec);
6478 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6482 New n_source = source as New;
6483 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6484 if (!n_source.Emit (ec, this)) {
6488 ec.EmitLoadFromPtr (type);
6500 ec.Emit (OpCodes.Dup);
6502 temp = new LocalTemporary (Type);
6508 ec.EmitStoreFromPtr (type);
6510 Variable.EmitAssign (ec);
6518 public override Expression EmitToField (EmitContext ec)
6520 HoistedVariable hv = GetHoistedVariable (ec);
6522 return hv.EmitToField (ec);
6525 return base.EmitToField (ec);
6528 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6530 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6533 public HoistedVariable GetHoistedVariable (EmitContext ec)
6535 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6538 public override string GetSignatureForError ()
6543 public bool IsHoisted {
6544 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6549 // Resolved reference to a local variable
6551 public class LocalVariableReference : VariableReference
6553 public LocalVariable local_info;
6555 public LocalVariableReference (LocalVariable li, Location l)
6557 this.local_info = li;
6561 public override VariableInfo VariableInfo {
6562 get { return local_info.VariableInfo; }
6565 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6567 return local_info.HoistedVariant;
6573 // A local variable is always fixed
6575 public override bool IsFixed {
6581 public override bool IsLockedByStatement {
6583 return local_info.IsLocked;
6586 local_info.IsLocked = value;
6590 public override bool IsRef {
6591 get { return false; }
6594 public override string Name {
6595 get { return local_info.Name; }
6600 public override void FlowAnalysis (FlowAnalysisContext fc)
6602 VariableInfo variable_info = VariableInfo;
6603 if (variable_info == null)
6606 if (fc.IsDefinitelyAssigned (variable_info))
6609 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6610 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6613 public override void SetHasAddressTaken ()
6615 local_info.SetHasAddressTaken ();
6618 void DoResolveBase (ResolveContext ec)
6620 eclass = ExprClass.Variable;
6621 type = local_info.Type;
6624 // If we are referencing a variable from the external block
6625 // flag it for capturing
6627 if (ec.MustCaptureVariable (local_info)) {
6628 if (local_info.AddressTaken) {
6629 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6630 } else if (local_info.IsFixed) {
6631 ec.Report.Error (1764, loc,
6632 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6633 GetSignatureForError ());
6636 if (ec.IsVariableCapturingRequired) {
6637 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6638 storey.CaptureLocalVariable (ec, local_info);
6643 protected override Expression DoResolve (ResolveContext ec)
6645 local_info.SetIsUsed ();
6649 if (local_info.Type == InternalType.VarOutType) {
6650 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6651 GetSignatureForError ());
6653 type = InternalType.ErrorType;
6659 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6662 // Don't be too pedantic when variable is used as out param or for some broken code
6663 // which uses property/indexer access to run some initialization
6665 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6666 local_info.SetIsUsed ();
6668 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6669 if (rhs == EmptyExpression.LValueMemberAccess) {
6670 // CS1654 already reported
6674 if (rhs == EmptyExpression.OutAccess) {
6675 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6676 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6677 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6678 } else if (rhs == EmptyExpression.UnaryAddress) {
6679 code = 459; msg = "Cannot take the address of {1} `{0}'";
6681 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6683 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6687 if (eclass == ExprClass.Unresolved)
6690 return base.DoResolveLValue (ec, rhs);
6693 public override int GetHashCode ()
6695 return local_info.GetHashCode ();
6698 public override bool Equals (object obj)
6700 LocalVariableReference lvr = obj as LocalVariableReference;
6704 return local_info == lvr.local_info;
6707 protected override ILocalVariable Variable {
6708 get { return local_info; }
6711 public override string ToString ()
6713 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6716 protected override void CloneTo (CloneContext clonectx, Expression t)
6723 /// This represents a reference to a parameter in the intermediate
6726 public class ParameterReference : VariableReference
6728 protected ParametersBlock.ParameterInfo pi;
6730 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6738 public override bool IsLockedByStatement {
6743 pi.IsLocked = value;
6747 public override bool IsRef {
6748 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6751 bool HasOutModifier {
6752 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6755 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6757 return pi.Parameter.HoistedVariant;
6761 // A ref or out parameter is classified as a moveable variable, even
6762 // if the argument given for the parameter is a fixed variable
6764 public override bool IsFixed {
6765 get { return !IsRef; }
6768 public override string Name {
6769 get { return Parameter.Name; }
6772 public Parameter Parameter {
6773 get { return pi.Parameter; }
6776 public override VariableInfo VariableInfo {
6777 get { return pi.VariableInfo; }
6780 protected override ILocalVariable Variable {
6781 get { return Parameter; }
6786 public override void AddressOf (EmitContext ec, AddressOp mode)
6789 // ParameterReferences might already be a reference
6796 base.AddressOf (ec, mode);
6799 public override void SetHasAddressTaken ()
6801 Parameter.HasAddressTaken = true;
6804 bool DoResolveBase (ResolveContext ec)
6806 if (eclass != ExprClass.Unresolved)
6809 type = pi.ParameterType;
6810 eclass = ExprClass.Variable;
6813 // If we are referencing a parameter from the external block
6814 // flag it for capturing
6816 if (ec.MustCaptureVariable (pi)) {
6817 if (Parameter.HasAddressTaken)
6818 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6821 ec.Report.Error (1628, loc,
6822 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6823 Name, ec.CurrentAnonymousMethod.ContainerType);
6826 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6827 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6828 storey.CaptureParameter (ec, pi, this);
6835 public override int GetHashCode ()
6837 return Name.GetHashCode ();
6840 public override bool Equals (object obj)
6842 ParameterReference pr = obj as ParameterReference;
6846 return Name == pr.Name;
6849 protected override void CloneTo (CloneContext clonectx, Expression target)
6855 public override Expression CreateExpressionTree (ResolveContext ec)
6857 HoistedVariable hv = GetHoistedVariable (ec);
6859 return hv.CreateExpressionTree ();
6861 return Parameter.ExpressionTreeVariableReference ();
6864 protected override Expression DoResolve (ResolveContext ec)
6866 if (!DoResolveBase (ec))
6872 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6874 if (!DoResolveBase (ec))
6877 if (Parameter.HoistedVariant != null)
6878 Parameter.HoistedVariant.IsAssigned = true;
6880 return base.DoResolveLValue (ec, right_side);
6883 public override void FlowAnalysis (FlowAnalysisContext fc)
6885 VariableInfo variable_info = VariableInfo;
6886 if (variable_info == null)
6889 if (fc.IsDefinitelyAssigned (variable_info))
6892 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6893 fc.SetVariableAssigned (variable_info);
6898 /// Invocation of methods or delegates.
6900 public class Invocation : ExpressionStatement
6902 public class Predefined : Invocation
6904 public Predefined (MethodGroupExpr expr, Arguments arguments)
6905 : base (expr, arguments)
6910 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6912 mg.BestCandidate.CheckObsoleteness (rc, loc);
6918 protected Arguments arguments;
6919 protected Expression expr;
6920 protected MethodGroupExpr mg;
6921 bool conditional_access_receiver;
6923 public Invocation (Expression expr, Arguments arguments)
6926 this.arguments = arguments;
6928 loc = expr.Location;
6933 public Arguments Arguments {
6939 public Expression Exp {
6945 public MethodGroupExpr MethodGroup {
6951 public override Location StartLocation {
6953 return expr.StartLocation;
6959 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6961 if (MethodGroup == null)
6964 var candidate = MethodGroup.BestCandidate;
6965 if (candidate == null || !(candidate.IsStatic || Exp is This))
6968 var args_count = arguments == null ? 0 : arguments.Count;
6969 if (args_count != body.Parameters.Count)
6972 var lambda_parameters = body.Block.Parameters.FixedParameters;
6973 for (int i = 0; i < args_count; ++i) {
6974 var pr = arguments[i].Expr as ParameterReference;
6978 if (lambda_parameters[i] != pr.Parameter)
6981 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6985 var emg = MethodGroup as ExtensionMethodGroupExpr;
6987 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6988 if (candidate.IsGeneric) {
6989 var targs = new TypeExpression [candidate.Arity];
6990 for (int i = 0; i < targs.Length; ++i) {
6991 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6994 mg.SetTypeArguments (null, new TypeArguments (targs));
7003 protected override void CloneTo (CloneContext clonectx, Expression t)
7005 Invocation target = (Invocation) t;
7007 if (arguments != null)
7008 target.arguments = arguments.Clone (clonectx);
7010 target.expr = expr.Clone (clonectx);
7013 public override bool ContainsEmitWithAwait ()
7015 if (arguments != null && arguments.ContainsEmitWithAwait ())
7018 return mg.ContainsEmitWithAwait ();
7021 public override Expression CreateExpressionTree (ResolveContext ec)
7023 Expression instance = mg.IsInstance ?
7024 mg.InstanceExpression.CreateExpressionTree (ec) :
7025 new NullLiteral (loc);
7027 var args = Arguments.CreateForExpressionTree (ec, arguments,
7029 mg.CreateExpressionTree (ec));
7031 return CreateExpressionFactoryCall (ec, "Call", args);
7034 void ResolveConditionalAccessReceiver (ResolveContext rc)
7036 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7037 conditional_access_receiver = true;
7041 bool statement_resolve;
7042 public override ExpressionStatement ResolveStatement (BlockContext bc)
7044 statement_resolve = true;
7045 var es = base.ResolveStatement (bc);
7046 statement_resolve = false;
7051 protected override Expression DoResolve (ResolveContext rc)
7053 ResolveConditionalAccessReceiver (rc);
7054 return DoResolveInvocation (rc);
7057 Expression DoResolveInvocation (ResolveContext ec)
7059 Expression member_expr;
7060 var atn = expr as ATypeNameExpression;
7062 var flags = default (ResolveContext.FlagsHandle);
7063 if (conditional_access_receiver)
7064 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7067 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7068 if (member_expr != null) {
7069 var name_of = member_expr as NameOf;
7070 if (name_of != null) {
7071 return name_of.ResolveOverload (ec, arguments);
7074 member_expr = member_expr.Resolve (ec);
7077 member_expr = expr.Resolve (ec);
7080 if (conditional_access_receiver)
7083 if (member_expr == null)
7087 // Next, evaluate all the expressions in the argument list
7089 bool dynamic_arg = false;
7090 if (arguments != null) {
7091 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7092 arguments.Resolve (ec, out dynamic_arg);
7096 TypeSpec expr_type = member_expr.Type;
7097 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7098 return DoResolveDynamic (ec, member_expr);
7100 mg = member_expr as MethodGroupExpr;
7101 Expression invoke = null;
7104 if (expr_type != null && expr_type.IsDelegate) {
7105 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7106 invoke = invoke.Resolve (ec);
7107 if (invoke == null || !dynamic_arg)
7110 if (member_expr is RuntimeValueExpression) {
7111 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7112 member_expr.Type.GetSignatureForError ());
7116 MemberExpr me = member_expr as MemberExpr;
7118 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7122 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7123 member_expr.GetSignatureForError ());
7128 if (invoke == null) {
7129 mg = DoResolveOverload (ec);
7135 return DoResolveDynamic (ec, member_expr);
7137 var method = mg.BestCandidate;
7138 type = mg.BestCandidateReturnType;
7139 if (conditional_access_receiver && !statement_resolve)
7140 type = LiftMemberType (ec, type);
7142 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7144 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7146 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7150 IsSpecialMethodInvocation (ec, method, loc);
7152 eclass = ExprClass.Value;
7156 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7159 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7161 args = dmb.Arguments;
7162 if (arguments != null)
7163 args.AddRange (arguments);
7164 } else if (mg == null) {
7165 if (arguments == null)
7166 args = new Arguments (1);
7170 args.Insert (0, new Argument (memberExpr));
7174 ec.Report.Error (1971, loc,
7175 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7180 if (arguments == null)
7181 args = new Arguments (1);
7185 MemberAccess ma = expr as MemberAccess;
7187 var inst = mg.InstanceExpression;
7188 var left_type = inst as TypeExpr;
7189 if (left_type != null) {
7190 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7191 } else if (inst != null) {
7193 // Any value type has to be pass as by-ref to get back the same
7194 // instance on which the member was called
7196 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7197 Argument.AType.Ref : Argument.AType.None;
7198 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7200 } else { // is SimpleName
7201 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7202 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7204 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7209 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7212 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7214 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7217 public override void FlowAnalysis (FlowAnalysisContext fc)
7219 if (mg.IsConditionallyExcluded)
7222 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7224 mg.FlowAnalysis (fc);
7226 if (arguments != null)
7227 arguments.FlowAnalysis (fc);
7229 if (conditional_access_receiver)
7230 fc.DefiniteAssignment = da;
7233 public override string GetSignatureForError ()
7235 return mg.GetSignatureForError ();
7238 public override bool HasConditionalAccess ()
7240 return expr.HasConditionalAccess ();
7244 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7245 // or the type dynamic, then the member is invocable
7247 public static bool IsMemberInvocable (MemberSpec member)
7249 switch (member.Kind) {
7250 case MemberKind.Event:
7252 case MemberKind.Field:
7253 case MemberKind.Property:
7254 var m = member as IInterfaceMemberSpec;
7255 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7261 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7263 if (!method.IsReservedMethod)
7266 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7269 ec.Report.SymbolRelatedToPreviousError (method);
7270 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7271 method.GetSignatureForError ());
7276 public override void Emit (EmitContext ec)
7278 if (mg.IsConditionallyExcluded)
7281 if (conditional_access_receiver)
7282 mg.EmitCall (ec, arguments, type, false);
7284 mg.EmitCall (ec, arguments, false);
7287 public override void EmitStatement (EmitContext ec)
7289 if (mg.IsConditionallyExcluded)
7292 if (conditional_access_receiver)
7293 mg.EmitCall (ec, arguments, type, true);
7295 mg.EmitCall (ec, arguments, true);
7298 public override SLE.Expression MakeExpression (BuilderContext ctx)
7300 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7303 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7306 throw new NotSupportedException ();
7308 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7309 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7313 public override object Accept (StructuralVisitor visitor)
7315 return visitor.Visit (this);
7320 // Implements simple new expression
7322 public class New : ExpressionStatement, IMemoryLocation
7324 protected Arguments arguments;
7327 // During bootstrap, it contains the RequestedType,
7328 // but if `type' is not null, it *might* contain a NewDelegate
7329 // (because of field multi-initialization)
7331 protected Expression RequestedType;
7333 protected MethodSpec method;
7335 public New (Expression requested_type, Arguments arguments, Location l)
7337 RequestedType = requested_type;
7338 this.arguments = arguments;
7343 public Arguments Arguments {
7350 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7352 public bool IsGeneratedStructConstructor {
7354 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7358 public Expression TypeExpression {
7360 return RequestedType;
7367 /// Converts complex core type syntax like 'new int ()' to simple constant
7369 public static Constant Constantify (TypeSpec t, Location loc)
7371 switch (t.BuiltinType) {
7372 case BuiltinTypeSpec.Type.Int:
7373 return new IntConstant (t, 0, loc);
7374 case BuiltinTypeSpec.Type.UInt:
7375 return new UIntConstant (t, 0, loc);
7376 case BuiltinTypeSpec.Type.Long:
7377 return new LongConstant (t, 0, loc);
7378 case BuiltinTypeSpec.Type.ULong:
7379 return new ULongConstant (t, 0, loc);
7380 case BuiltinTypeSpec.Type.Float:
7381 return new FloatConstant (t, 0, loc);
7382 case BuiltinTypeSpec.Type.Double:
7383 return new DoubleConstant (t, 0, loc);
7384 case BuiltinTypeSpec.Type.Short:
7385 return new ShortConstant (t, 0, loc);
7386 case BuiltinTypeSpec.Type.UShort:
7387 return new UShortConstant (t, 0, loc);
7388 case BuiltinTypeSpec.Type.SByte:
7389 return new SByteConstant (t, 0, loc);
7390 case BuiltinTypeSpec.Type.Byte:
7391 return new ByteConstant (t, 0, loc);
7392 case BuiltinTypeSpec.Type.Char:
7393 return new CharConstant (t, '\0', loc);
7394 case BuiltinTypeSpec.Type.Bool:
7395 return new BoolConstant (t, false, loc);
7396 case BuiltinTypeSpec.Type.Decimal:
7397 return new DecimalConstant (t, 0, loc);
7401 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7403 if (t.IsNullableType)
7404 return Nullable.LiftedNull.Create (t, loc);
7409 public override bool ContainsEmitWithAwait ()
7411 return arguments != null && arguments.ContainsEmitWithAwait ();
7415 // Checks whether the type is an interface that has the
7416 // [ComImport, CoClass] attributes and must be treated
7419 public Expression CheckComImport (ResolveContext ec)
7421 if (!type.IsInterface)
7425 // Turn the call into:
7426 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7428 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7429 if (real_class == null)
7432 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7433 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7434 return cast.Resolve (ec);
7437 public override Expression CreateExpressionTree (ResolveContext ec)
7440 if (method == null) {
7441 args = new Arguments (1);
7442 args.Add (new Argument (new TypeOf (type, loc)));
7444 args = Arguments.CreateForExpressionTree (ec,
7445 arguments, new TypeOfMethod (method, loc));
7448 return CreateExpressionFactoryCall (ec, "New", args);
7451 protected override Expression DoResolve (ResolveContext ec)
7453 type = RequestedType.ResolveAsType (ec);
7457 eclass = ExprClass.Value;
7459 if (type.IsPointer) {
7460 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7461 type.GetSignatureForError ());
7465 if (arguments == null) {
7466 Constant c = Constantify (type, RequestedType.Location);
7468 return ReducedExpression.Create (c, this);
7471 if (type.IsDelegate) {
7472 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7475 var tparam = type as TypeParameterSpec;
7476 if (tparam != null) {
7478 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7479 // where type parameter constraint is inflated to struct
7481 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7482 ec.Report.Error (304, loc,
7483 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7484 type.GetSignatureForError ());
7487 if ((arguments != null) && (arguments.Count != 0)) {
7488 ec.Report.Error (417, loc,
7489 "`{0}': cannot provide arguments when creating an instance of a variable type",
7490 type.GetSignatureForError ());
7496 if (type.IsStatic) {
7497 ec.Report.SymbolRelatedToPreviousError (type);
7498 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7502 if (type.IsInterface || type.IsAbstract){
7503 if (!TypeManager.IsGenericType (type)) {
7504 RequestedType = CheckComImport (ec);
7505 if (RequestedType != null)
7506 return RequestedType;
7509 ec.Report.SymbolRelatedToPreviousError (type);
7510 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7515 if (arguments != null) {
7516 arguments.Resolve (ec, out dynamic);
7521 method = ConstructorLookup (ec, type, ref arguments, loc);
7524 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7525 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7531 void DoEmitTypeParameter (EmitContext ec)
7533 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7537 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7538 ec.Emit (OpCodes.Call, ctor_factory);
7542 // This Emit can be invoked in two contexts:
7543 // * As a mechanism that will leave a value on the stack (new object)
7544 // * As one that wont (init struct)
7546 // If we are dealing with a ValueType, we have a few
7547 // situations to deal with:
7549 // * The target is a ValueType, and we have been provided
7550 // the instance (this is easy, we are being assigned).
7552 // * The target of New is being passed as an argument,
7553 // to a boxing operation or a function that takes a
7556 // In this case, we need to create a temporary variable
7557 // that is the argument of New.
7559 // Returns whether a value is left on the stack
7561 // *** Implementation note ***
7563 // To benefit from this optimization, each assignable expression
7564 // has to manually cast to New and call this Emit.
7566 // TODO: It's worth to implement it for arrays and fields
7568 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7570 bool is_value_type = type.IsStructOrEnum;
7571 VariableReference vr = target as VariableReference;
7573 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7575 if (target != null && is_value_type && (vr != null || method == null)) {
7576 if (prepare_await) {
7577 arguments = arguments.Emit (ec, false, true);
7578 prepare_await = false;
7581 target.AddressOf (ec, AddressOp.Store);
7582 } else if (vr != null && vr.IsRef) {
7586 if (arguments != null) {
7588 arguments = arguments.Emit (ec, false, true);
7590 arguments.Emit (ec);
7593 if (is_value_type) {
7594 if (method == null) {
7595 ec.Emit (OpCodes.Initobj, type);
7600 ec.MarkCallEntry (loc);
7601 ec.Emit (OpCodes.Call, method);
7606 if (type is TypeParameterSpec) {
7607 DoEmitTypeParameter (ec);
7611 ec.MarkCallEntry (loc);
7612 ec.Emit (OpCodes.Newobj, method);
7616 public override void Emit (EmitContext ec)
7618 LocalTemporary v = null;
7619 if (method == null && type.IsStructOrEnum) {
7620 // TODO: Use temporary variable from pool
7621 v = new LocalTemporary (type);
7628 public override void EmitStatement (EmitContext ec)
7630 LocalTemporary v = null;
7631 if (method == null && TypeSpec.IsValueType (type)) {
7632 // TODO: Use temporary variable from pool
7633 v = new LocalTemporary (type);
7637 ec.Emit (OpCodes.Pop);
7640 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7645 public override void FlowAnalysis (FlowAnalysisContext fc)
7647 if (arguments != null)
7648 arguments.FlowAnalysis (fc);
7651 public void AddressOf (EmitContext ec, AddressOp mode)
7653 EmitAddressOf (ec, mode);
7656 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7658 LocalTemporary value_target = new LocalTemporary (type);
7660 if (type is TypeParameterSpec) {
7661 DoEmitTypeParameter (ec);
7662 value_target.Store (ec);
7663 value_target.AddressOf (ec, mode);
7664 return value_target;
7667 value_target.AddressOf (ec, AddressOp.Store);
7669 if (method == null) {
7670 ec.Emit (OpCodes.Initobj, type);
7672 if (arguments != null)
7673 arguments.Emit (ec);
7675 ec.Emit (OpCodes.Call, method);
7678 value_target.AddressOf (ec, mode);
7679 return value_target;
7682 protected override void CloneTo (CloneContext clonectx, Expression t)
7684 New target = (New) t;
7686 target.RequestedType = RequestedType.Clone (clonectx);
7687 if (arguments != null){
7688 target.arguments = arguments.Clone (clonectx);
7692 public override SLE.Expression MakeExpression (BuilderContext ctx)
7695 return base.MakeExpression (ctx);
7697 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7701 public override object Accept (StructuralVisitor visitor)
7703 return visitor.Visit (this);
7708 // Array initializer expression, the expression is allowed in
7709 // variable or field initialization only which makes it tricky as
7710 // the type has to be infered based on the context either from field
7711 // type or variable type (think of multiple declarators)
7713 public class ArrayInitializer : Expression
7715 List<Expression> elements;
7716 BlockVariable variable;
7718 public ArrayInitializer (List<Expression> init, Location loc)
7724 public ArrayInitializer (int count, Location loc)
7725 : this (new List<Expression> (count), loc)
7729 public ArrayInitializer (Location loc)
7737 get { return elements.Count; }
7740 public List<Expression> Elements {
7746 public Expression this [int index] {
7748 return elements [index];
7752 public BlockVariable VariableDeclaration {
7763 public void Add (Expression expr)
7765 elements.Add (expr);
7768 public override bool ContainsEmitWithAwait ()
7770 throw new NotSupportedException ();
7773 public override Expression CreateExpressionTree (ResolveContext ec)
7775 throw new NotSupportedException ("ET");
7778 protected override void CloneTo (CloneContext clonectx, Expression t)
7780 var target = (ArrayInitializer) t;
7782 target.elements = new List<Expression> (elements.Count);
7783 foreach (var element in elements)
7784 target.elements.Add (element.Clone (clonectx));
7787 protected override Expression DoResolve (ResolveContext rc)
7789 var current_field = rc.CurrentMemberDefinition as FieldBase;
7790 TypeExpression type;
7791 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7792 type = new TypeExpression (current_field.MemberType, current_field.Location);
7793 } else if (variable != null) {
7794 if (variable.TypeExpression is VarExpr) {
7795 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7796 return EmptyExpression.Null;
7799 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7801 throw new NotImplementedException ("Unexpected array initializer context");
7804 return new ArrayCreation (type, this).Resolve (rc);
7807 public override void Emit (EmitContext ec)
7809 throw new InternalErrorException ("Missing Resolve call");
7812 public override void FlowAnalysis (FlowAnalysisContext fc)
7814 throw new InternalErrorException ("Missing Resolve call");
7817 public override object Accept (StructuralVisitor visitor)
7819 return visitor.Visit (this);
7824 /// 14.5.10.2: Represents an array creation expression.
7828 /// There are two possible scenarios here: one is an array creation
7829 /// expression that specifies the dimensions and optionally the
7830 /// initialization data and the other which does not need dimensions
7831 /// specified but where initialization data is mandatory.
7833 public class ArrayCreation : Expression
7835 FullNamedExpression requested_base_type;
7836 ArrayInitializer initializers;
7839 // The list of Argument types.
7840 // This is used to construct the `newarray' or constructor signature
7842 protected List<Expression> arguments;
7844 protected TypeSpec array_element_type;
7846 protected int dimensions;
7847 protected readonly ComposedTypeSpecifier rank;
7848 Expression first_emit;
7849 LocalTemporary first_emit_temp;
7851 protected List<Expression> array_data;
7853 Dictionary<int, int> bounds;
7856 // The number of constants in array initializers
7857 int const_initializers_count;
7858 bool only_constant_initializers;
7860 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7861 : this (requested_base_type, rank, initializers, l)
7863 arguments = new List<Expression> (exprs);
7864 num_arguments = arguments.Count;
7868 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7870 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7872 this.requested_base_type = requested_base_type;
7874 this.initializers = initializers;
7878 num_arguments = rank.Dimension;
7882 // For compiler generated single dimensional arrays only
7884 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7885 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7890 // For expressions like int[] foo = { 1, 2, 3 };
7892 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7893 : this (requested_base_type, null, initializers, initializers.Location)
7897 public bool NoEmptyInterpolation { get; set; }
7899 public ComposedTypeSpecifier Rank {
7905 public FullNamedExpression TypeExpression {
7907 return this.requested_base_type;
7911 public ArrayInitializer Initializers {
7913 return this.initializers;
7917 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7919 if (initializers != null && bounds == null) {
7921 // We use this to store all the data values in the order in which we
7922 // will need to store them in the byte blob later
7924 array_data = new List<Expression> (probe.Count);
7925 bounds = new Dictionary<int, int> ();
7928 if (specified_dims) {
7929 Expression a = arguments [idx];
7934 a = ConvertExpressionToArrayIndex (ec, a);
7940 if (initializers != null) {
7941 Constant c = a as Constant;
7942 if (c == null && a is ArrayIndexCast)
7943 c = ((ArrayIndexCast) a).Child as Constant;
7946 ec.Report.Error (150, a.Location, "A constant value is expected");
7952 value = System.Convert.ToInt32 (c.GetValue ());
7954 ec.Report.Error (150, a.Location, "A constant value is expected");
7958 // TODO: probe.Count does not fit ulong in
7959 if (value != probe.Count) {
7960 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7964 bounds[idx] = value;
7968 if (initializers == null)
7971 for (int i = 0; i < probe.Count; ++i) {
7973 if (o is ArrayInitializer) {
7974 var sub_probe = o as ArrayInitializer;
7975 if (idx + 1 >= dimensions){
7976 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7980 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7981 if (!bounds.ContainsKey(idx + 1))
7982 bounds[idx + 1] = sub_probe.Count;
7984 if (bounds[idx + 1] != sub_probe.Count) {
7985 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7989 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7992 } else if (child_bounds > 1) {
7993 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7995 Expression element = ResolveArrayElement (ec, o);
7996 if (element == null)
7999 // Initializers with the default values can be ignored
8000 Constant c = element as Constant;
8002 if (!c.IsDefaultInitializer (array_element_type)) {
8003 ++const_initializers_count;
8006 only_constant_initializers = false;
8009 array_data.Add (element);
8016 public override bool ContainsEmitWithAwait ()
8018 foreach (var arg in arguments) {
8019 if (arg.ContainsEmitWithAwait ())
8023 return InitializersContainAwait ();
8026 public override Expression CreateExpressionTree (ResolveContext ec)
8030 if (array_data == null) {
8031 args = new Arguments (arguments.Count + 1);
8032 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8033 foreach (Expression a in arguments)
8034 args.Add (new Argument (a.CreateExpressionTree (ec)));
8036 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8039 if (dimensions > 1) {
8040 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8044 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8045 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8046 if (array_data != null) {
8047 for (int i = 0; i < array_data.Count; ++i) {
8048 Expression e = array_data [i];
8049 args.Add (new Argument (e.CreateExpressionTree (ec)));
8053 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8056 void UpdateIndices (ResolveContext rc)
8059 for (var probe = initializers; probe != null;) {
8060 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8062 bounds[i++] = probe.Count;
8064 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8065 probe = (ArrayInitializer) probe[0];
8066 } else if (dimensions > i) {
8074 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8076 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8079 public override void FlowAnalysis (FlowAnalysisContext fc)
8081 foreach (var arg in arguments)
8082 arg.FlowAnalysis (fc);
8084 if (array_data != null) {
8085 foreach (var ad in array_data)
8086 ad.FlowAnalysis (fc);
8090 bool InitializersContainAwait ()
8092 if (array_data == null)
8095 foreach (var expr in array_data) {
8096 if (expr.ContainsEmitWithAwait ())
8103 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8105 element = element.Resolve (ec);
8106 if (element == null)
8109 var te = element as CompoundAssign.TargetExpression;
8111 for (int i = 1; i < initializers.Count; ++i) {
8112 if (initializers [i].ContainsEmitWithAwait ()) {
8113 te.RequiresEmitWithAwait = true;
8118 if (!te.RequiresEmitWithAwait) {
8119 if (first_emit != null)
8120 throw new InternalErrorException ("Can only handle one mutator at a time");
8121 first_emit = element;
8122 element = first_emit_temp = new LocalTemporary (element.Type);
8126 return Convert.ImplicitConversionRequired (
8127 ec, element, array_element_type, loc);
8130 protected bool ResolveInitializers (ResolveContext ec)
8133 only_constant_initializers = true;
8136 if (arguments != null) {
8138 for (int i = 0; i < arguments.Count; ++i) {
8139 res &= CheckIndices (ec, initializers, i, true, dimensions);
8140 if (initializers != null)
8147 arguments = new List<Expression> ();
8149 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8158 // Resolved the type of the array
8160 bool ResolveArrayType (ResolveContext ec)
8165 FullNamedExpression array_type_expr;
8166 if (num_arguments > 0) {
8167 array_type_expr = new ComposedCast (requested_base_type, rank);
8169 array_type_expr = requested_base_type;
8172 type = array_type_expr.ResolveAsType (ec);
8173 if (array_type_expr == null)
8176 var ac = type as ArrayContainer;
8178 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8182 array_element_type = ac.Element;
8183 dimensions = ac.Rank;
8188 protected override Expression DoResolve (ResolveContext ec)
8193 if (!ResolveArrayType (ec))
8197 // validate the initializers and fill in any missing bits
8199 if (!ResolveInitializers (ec))
8202 eclass = ExprClass.Value;
8206 byte [] MakeByteBlob ()
8211 int count = array_data.Count;
8213 TypeSpec element_type = array_element_type;
8214 if (element_type.IsEnum)
8215 element_type = EnumSpec.GetUnderlyingType (element_type);
8217 factor = BuiltinTypeSpec.GetSize (element_type);
8219 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8221 data = new byte [(count * factor + 3) & ~3];
8224 for (int i = 0; i < count; ++i) {
8225 var c = array_data[i] as Constant;
8231 object v = c.GetValue ();
8233 switch (element_type.BuiltinType) {
8234 case BuiltinTypeSpec.Type.Long:
8235 long lval = (long) v;
8237 for (int j = 0; j < factor; ++j) {
8238 data[idx + j] = (byte) (lval & 0xFF);
8242 case BuiltinTypeSpec.Type.ULong:
8243 ulong ulval = (ulong) v;
8245 for (int j = 0; j < factor; ++j) {
8246 data[idx + j] = (byte) (ulval & 0xFF);
8247 ulval = (ulval >> 8);
8250 case BuiltinTypeSpec.Type.Float:
8251 var fval = SingleConverter.SingleToInt32Bits((float) v);
8253 data[idx] = (byte) (fval & 0xff);
8254 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8255 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8256 data[idx + 3] = (byte) (fval >> 24);
8258 case BuiltinTypeSpec.Type.Double:
8259 element = BitConverter.GetBytes ((double) v);
8261 for (int j = 0; j < factor; ++j)
8262 data[idx + j] = element[j];
8264 // FIXME: Handle the ARM float format.
8265 if (!BitConverter.IsLittleEndian)
8266 System.Array.Reverse (data, idx, 8);
8268 case BuiltinTypeSpec.Type.Char:
8269 int chval = (int) ((char) v);
8271 data[idx] = (byte) (chval & 0xff);
8272 data[idx + 1] = (byte) (chval >> 8);
8274 case BuiltinTypeSpec.Type.Short:
8275 int sval = (int) ((short) v);
8277 data[idx] = (byte) (sval & 0xff);
8278 data[idx + 1] = (byte) (sval >> 8);
8280 case BuiltinTypeSpec.Type.UShort:
8281 int usval = (int) ((ushort) v);
8283 data[idx] = (byte) (usval & 0xff);
8284 data[idx + 1] = (byte) (usval >> 8);
8286 case BuiltinTypeSpec.Type.Int:
8289 data[idx] = (byte) (val & 0xff);
8290 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8291 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8292 data[idx + 3] = (byte) (val >> 24);
8294 case BuiltinTypeSpec.Type.UInt:
8295 uint uval = (uint) v;
8297 data[idx] = (byte) (uval & 0xff);
8298 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8299 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8300 data[idx + 3] = (byte) (uval >> 24);
8302 case BuiltinTypeSpec.Type.SByte:
8303 data[idx] = (byte) (sbyte) v;
8305 case BuiltinTypeSpec.Type.Byte:
8306 data[idx] = (byte) v;
8308 case BuiltinTypeSpec.Type.Bool:
8309 data[idx] = (byte) ((bool) v ? 1 : 0);
8311 case BuiltinTypeSpec.Type.Decimal:
8312 int[] bits = Decimal.GetBits ((decimal) v);
8315 // FIXME: For some reason, this doesn't work on the MS runtime.
8316 int[] nbits = new int[4];
8322 for (int j = 0; j < 4; j++) {
8323 data[p++] = (byte) (nbits[j] & 0xff);
8324 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8325 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8326 data[p++] = (byte) (nbits[j] >> 24);
8330 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8339 public override SLE.Expression MakeExpression (BuilderContext ctx)
8342 return base.MakeExpression (ctx);
8344 var initializers = new SLE.Expression [array_data.Count];
8345 for (var i = 0; i < initializers.Length; i++) {
8346 if (array_data [i] == null)
8347 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8349 initializers [i] = array_data [i].MakeExpression (ctx);
8352 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8357 // Emits the initializers for the array
8359 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8361 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8366 // First, the static data
8368 byte [] data = MakeByteBlob ();
8369 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8371 if (stackArray == null) {
8372 ec.Emit (OpCodes.Dup);
8374 stackArray.Emit (ec);
8377 ec.Emit (OpCodes.Ldtoken, fb);
8378 ec.Emit (OpCodes.Call, m);
8383 // Emits pieces of the array that can not be computed at compile
8384 // time (variables and string locations).
8386 // This always expect the top value on the stack to be the array
8388 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8390 int dims = bounds.Count;
8391 var current_pos = new int [dims];
8393 for (int i = 0; i < array_data.Count; i++){
8395 Expression e = array_data [i];
8396 var c = e as Constant;
8398 // Constant can be initialized via StaticInitializer
8399 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8403 if (stackArray != null) {
8404 if (e.ContainsEmitWithAwait ()) {
8405 e = e.EmitToField (ec);
8408 stackArray.EmitLoad (ec);
8410 ec.Emit (OpCodes.Dup);
8413 for (int idx = 0; idx < dims; idx++)
8414 ec.EmitInt (current_pos [idx]);
8417 // If we are dealing with a struct, get the
8418 // address of it, so we can store it.
8420 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8421 ec.Emit (OpCodes.Ldelema, etype);
8425 ec.EmitArrayStore ((ArrayContainer) type);
8431 for (int j = dims - 1; j >= 0; j--){
8433 if (current_pos [j] < bounds [j])
8435 current_pos [j] = 0;
8439 if (stackArray != null)
8440 stackArray.PrepareCleanup (ec);
8443 public override void Emit (EmitContext ec)
8445 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8448 var await_field = EmitToFieldSource (ec);
8449 if (await_field != null)
8450 await_field.Emit (ec);
8453 bool EmitOptimizedEmpty (EmitContext ec)
8455 if (arguments.Count != 1 || dimensions != 1)
8458 var c = arguments [0] as Constant;
8459 if (c == null || !c.IsZeroInteger)
8462 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8463 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8466 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8467 ec.Emit (OpCodes.Call, m);
8471 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8473 if (first_emit != null) {
8474 first_emit.Emit (ec);
8475 first_emit_temp.Store (ec);
8478 StackFieldExpr await_stack_field;
8479 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8480 await_stack_field = ec.GetTemporaryField (type);
8483 await_stack_field = null;
8486 EmitExpressionsList (ec, arguments);
8488 ec.EmitArrayNew ((ArrayContainer) type);
8490 if (initializers == null)
8491 return await_stack_field;
8493 if (await_stack_field != null)
8494 await_stack_field.EmitAssignFromStack (ec);
8498 // Emit static initializer for arrays which contain more than 2 items and
8499 // the static initializer will initialize at least 25% of array values or there
8500 // is more than 10 items to be initialized
8502 // NOTE: const_initializers_count does not contain default constant values.
8504 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8505 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8506 EmitStaticInitializers (ec, await_stack_field);
8508 if (!only_constant_initializers)
8509 EmitDynamicInitializers (ec, false, await_stack_field);
8513 EmitDynamicInitializers (ec, true, await_stack_field);
8516 if (first_emit_temp != null)
8517 first_emit_temp.Release (ec);
8519 return await_stack_field;
8522 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8524 // no multi dimensional or jagged arrays
8525 if (arguments.Count != 1 || array_element_type.IsArray) {
8526 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8530 // No array covariance, except for array -> object
8531 if (type != targetType) {
8532 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8533 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8537 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8538 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8543 // Single dimensional array of 0 size
8544 if (array_data == null) {
8545 IntConstant ic = arguments[0] as IntConstant;
8546 if (ic == null || !ic.IsDefaultValue) {
8547 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8555 enc.Encode (array_data.Count);
8556 foreach (var element in array_data) {
8557 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8561 protected override void CloneTo (CloneContext clonectx, Expression t)
8563 ArrayCreation target = (ArrayCreation) t;
8565 if (requested_base_type != null)
8566 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8568 if (arguments != null){
8569 target.arguments = new List<Expression> (arguments.Count);
8570 foreach (Expression e in arguments)
8571 target.arguments.Add (e.Clone (clonectx));
8574 if (initializers != null)
8575 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8578 public override object Accept (StructuralVisitor visitor)
8580 return visitor.Visit (this);
8585 // Represents an implicitly typed array epxression
8587 class ImplicitlyTypedArrayCreation : ArrayCreation
8589 TypeInferenceContext best_type_inference;
8591 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8592 : base (null, rank, initializers, loc)
8596 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8597 : base (null, initializers, loc)
8601 protected override Expression DoResolve (ResolveContext ec)
8606 dimensions = rank.Dimension;
8608 best_type_inference = new TypeInferenceContext ();
8610 if (!ResolveInitializers (ec))
8613 best_type_inference.FixAllTypes (ec);
8614 array_element_type = best_type_inference.InferredTypeArguments[0];
8615 best_type_inference = null;
8617 if (array_element_type == null ||
8618 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8619 arguments.Count != rank.Dimension) {
8620 ec.Report.Error (826, loc,
8621 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8626 // At this point we found common base type for all initializer elements
8627 // but we have to be sure that all static initializer elements are of
8630 UnifyInitializerElement (ec);
8632 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8633 eclass = ExprClass.Value;
8638 // Converts static initializer only
8640 void UnifyInitializerElement (ResolveContext ec)
8642 for (int i = 0; i < array_data.Count; ++i) {
8643 Expression e = array_data[i];
8645 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8649 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8651 element = element.Resolve (ec);
8652 if (element != null)
8653 best_type_inference.AddCommonTypeBound (element.Type);
8659 sealed class CompilerGeneratedThis : This
8661 public CompilerGeneratedThis (TypeSpec type, Location loc)
8667 protected override Expression DoResolve (ResolveContext rc)
8669 eclass = ExprClass.Variable;
8671 var block = rc.CurrentBlock;
8672 if (block != null) {
8673 var top = block.ParametersBlock.TopBlock;
8674 if (top.ThisVariable != null)
8675 variable_info = top.ThisVariable.VariableInfo;
8682 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8684 return DoResolve (rc);
8687 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8694 /// Represents the `this' construct
8697 public class This : VariableReference
8699 sealed class ThisVariable : ILocalVariable
8701 public static readonly ILocalVariable Instance = new ThisVariable ();
8703 public void Emit (EmitContext ec)
8708 public void EmitAssign (EmitContext ec)
8710 throw new InvalidOperationException ();
8713 public void EmitAddressOf (EmitContext ec)
8719 protected VariableInfo variable_info;
8721 public This (Location loc)
8728 public override string Name {
8729 get { return "this"; }
8732 public override bool IsLockedByStatement {
8740 public override bool IsRef {
8741 get { return type.IsStruct; }
8744 public override bool IsSideEffectFree {
8750 protected override ILocalVariable Variable {
8751 get { return ThisVariable.Instance; }
8754 public override VariableInfo VariableInfo {
8755 get { return variable_info; }
8758 public override bool IsFixed {
8759 get { return false; }
8764 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8767 // It's null for all cases when we don't need to check `this'
8768 // definitive assignment
8770 if (variable_info == null)
8773 if (fc.IsDefinitelyAssigned (variable_info))
8776 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8779 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8781 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8782 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8783 } else if (ec.CurrentAnonymousMethod != null) {
8784 ec.Report.Error (1673, loc,
8785 "Anonymous methods inside structs cannot access instance members of `this'. " +
8786 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8788 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8792 public override void FlowAnalysis (FlowAnalysisContext fc)
8794 CheckStructThisDefiniteAssignment (fc);
8797 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8802 AnonymousMethodStorey storey = ae.Storey;
8803 return storey != null ? storey.HoistedThis : null;
8806 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8808 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8811 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8814 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8820 public virtual void ResolveBase (ResolveContext ec)
8822 eclass = ExprClass.Variable;
8823 type = ec.CurrentType;
8825 if (!IsThisAvailable (ec, false)) {
8826 Error_ThisNotAvailable (ec);
8830 var block = ec.CurrentBlock;
8831 if (block != null) {
8832 var top = block.ParametersBlock.TopBlock;
8833 if (top.ThisVariable != null)
8834 variable_info = top.ThisVariable.VariableInfo;
8836 AnonymousExpression am = ec.CurrentAnonymousMethod;
8837 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8839 // Hoisted this is almost like hoisted variable but not exactly. When
8840 // there is no variable hoisted we can simply emit an instance method
8841 // without lifting this into a storey. Unfotunatelly this complicates
8842 // things in other cases because we don't know where this will be hoisted
8843 // until top-level block is fully resolved
8845 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8846 am.SetHasThisAccess ();
8851 protected override Expression DoResolve (ResolveContext ec)
8857 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8859 if (eclass == ExprClass.Unresolved)
8863 if (right_side == EmptyExpression.UnaryAddress)
8864 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8865 else if (right_side == EmptyExpression.OutAccess)
8866 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8868 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8874 public override int GetHashCode()
8876 throw new NotImplementedException ();
8879 public override bool Equals (object obj)
8881 This t = obj as This;
8888 protected override void CloneTo (CloneContext clonectx, Expression t)
8893 public override void SetHasAddressTaken ()
8898 public override object Accept (StructuralVisitor visitor)
8900 return visitor.Visit (this);
8905 /// Represents the `__arglist' construct
8907 public class ArglistAccess : Expression
8909 public ArglistAccess (Location loc)
8914 protected override void CloneTo (CloneContext clonectx, Expression target)
8919 public override bool ContainsEmitWithAwait ()
8924 public override Expression CreateExpressionTree (ResolveContext ec)
8926 throw new NotSupportedException ("ET");
8929 protected override Expression DoResolve (ResolveContext ec)
8931 eclass = ExprClass.Variable;
8932 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8934 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8935 ec.Report.Error (190, loc,
8936 "The __arglist construct is valid only within a variable argument method");
8942 public override void Emit (EmitContext ec)
8944 ec.Emit (OpCodes.Arglist);
8947 public override object Accept (StructuralVisitor visitor)
8949 return visitor.Visit (this);
8954 /// Represents the `__arglist (....)' construct
8956 public class Arglist : Expression
8958 Arguments arguments;
8960 public Arglist (Location loc)
8965 public Arglist (Arguments args, Location l)
8971 public Arguments Arguments {
8977 public MetaType[] ArgumentTypes {
8979 if (arguments == null)
8980 return MetaType.EmptyTypes;
8982 var retval = new MetaType[arguments.Count];
8983 for (int i = 0; i < retval.Length; i++)
8984 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8990 public override bool ContainsEmitWithAwait ()
8992 throw new NotImplementedException ();
8995 public override Expression CreateExpressionTree (ResolveContext ec)
8997 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9001 protected override Expression DoResolve (ResolveContext ec)
9003 eclass = ExprClass.Variable;
9004 type = InternalType.Arglist;
9005 if (arguments != null) {
9006 bool dynamic; // Can be ignored as there is always only 1 overload
9007 arguments.Resolve (ec, out dynamic);
9013 public override void Emit (EmitContext ec)
9015 if (arguments != null)
9016 arguments.Emit (ec);
9019 protected override void CloneTo (CloneContext clonectx, Expression t)
9021 Arglist target = (Arglist) t;
9023 if (arguments != null)
9024 target.arguments = arguments.Clone (clonectx);
9027 public override object Accept (StructuralVisitor visitor)
9029 return visitor.Visit (this);
9033 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9035 FullNamedExpression texpr;
9037 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9044 public FullNamedExpression TypeExpression {
9050 public override bool ContainsEmitWithAwait ()
9055 public void AddressOf (EmitContext ec, AddressOp mode)
9058 ec.Emit (OpCodes.Refanyval, type);
9061 protected override Expression DoResolve (ResolveContext rc)
9063 expr = expr.Resolve (rc);
9064 type = texpr.ResolveAsType (rc);
9065 if (expr == null || type == null)
9068 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9069 eclass = ExprClass.Variable;
9073 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9075 return DoResolve (rc);
9078 public override void Emit (EmitContext ec)
9081 ec.Emit (OpCodes.Refanyval, type);
9082 ec.EmitLoadFromPtr (type);
9085 public void Emit (EmitContext ec, bool leave_copy)
9087 throw new NotImplementedException ();
9090 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9093 ec.Emit (OpCodes.Refanyval, type);
9096 LocalTemporary temporary = null;
9098 ec.Emit (OpCodes.Dup);
9099 temporary = new LocalTemporary (source.Type);
9100 temporary.Store (ec);
9103 ec.EmitStoreFromPtr (type);
9105 if (temporary != null) {
9106 temporary.Emit (ec);
9107 temporary.Release (ec);
9111 public override object Accept (StructuralVisitor visitor)
9113 return visitor.Visit (this);
9117 public class RefTypeExpr : ShimExpression
9119 public RefTypeExpr (Expression expr, Location loc)
9125 protected override Expression DoResolve (ResolveContext rc)
9127 expr = expr.Resolve (rc);
9131 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9135 type = rc.BuiltinTypes.Type;
9136 eclass = ExprClass.Value;
9140 public override void Emit (EmitContext ec)
9143 ec.Emit (OpCodes.Refanytype);
9144 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9146 ec.Emit (OpCodes.Call, m);
9149 public override object Accept (StructuralVisitor visitor)
9151 return visitor.Visit (this);
9155 public class MakeRefExpr : ShimExpression
9157 public MakeRefExpr (Expression expr, Location loc)
9163 public override bool ContainsEmitWithAwait ()
9165 throw new NotImplementedException ();
9168 protected override Expression DoResolve (ResolveContext rc)
9170 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9171 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9172 eclass = ExprClass.Value;
9176 public override void Emit (EmitContext ec)
9178 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9179 ec.Emit (OpCodes.Mkrefany, expr.Type);
9182 public override object Accept (StructuralVisitor visitor)
9184 return visitor.Visit (this);
9189 /// Implements the typeof operator
9191 public class TypeOf : Expression {
9192 FullNamedExpression QueriedType;
9195 public TypeOf (FullNamedExpression queried_type, Location l)
9197 QueriedType = queried_type;
9202 // Use this constructor for any compiler generated typeof expression
9204 public TypeOf (TypeSpec type, Location loc)
9206 this.typearg = type;
9212 public override bool IsSideEffectFree {
9218 public TypeSpec TypeArgument {
9224 public FullNamedExpression TypeExpression {
9233 protected override void CloneTo (CloneContext clonectx, Expression t)
9235 TypeOf target = (TypeOf) t;
9236 if (QueriedType != null)
9237 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9240 public override bool ContainsEmitWithAwait ()
9245 public override Expression CreateExpressionTree (ResolveContext ec)
9247 Arguments args = new Arguments (2);
9248 args.Add (new Argument (this));
9249 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9250 return CreateExpressionFactoryCall (ec, "Constant", args);
9253 protected override Expression DoResolve (ResolveContext ec)
9255 if (eclass != ExprClass.Unresolved)
9258 if (typearg == null) {
9260 // Pointer types are allowed without explicit unsafe, they are just tokens
9262 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9263 typearg = QueriedType.ResolveAsType (ec, true);
9266 if (typearg == null)
9269 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9270 ec.Report.Error (1962, QueriedType.Location,
9271 "The typeof operator cannot be used on the dynamic type");
9275 type = ec.BuiltinTypes.Type;
9277 // Even though what is returned is a type object, it's treated as a value by the compiler.
9278 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9279 eclass = ExprClass.Value;
9283 static bool ContainsDynamicType (TypeSpec type)
9285 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9288 var element_container = type as ElementTypeSpec;
9289 if (element_container != null)
9290 return ContainsDynamicType (element_container.Element);
9292 foreach (var t in type.TypeArguments) {
9293 if (ContainsDynamicType (t)) {
9301 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9303 // Target type is not System.Type therefore must be object
9304 // and we need to use different encoding sequence
9305 if (targetType != type)
9308 if (typearg is InflatedTypeSpec) {
9311 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9312 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9313 typearg.GetSignatureForError ());
9317 gt = gt.DeclaringType;
9318 } while (gt != null);
9321 if (ContainsDynamicType (typearg)) {
9322 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9326 enc.EncodeTypeName (typearg);
9329 public override void Emit (EmitContext ec)
9331 ec.Emit (OpCodes.Ldtoken, typearg);
9332 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9334 ec.Emit (OpCodes.Call, m);
9337 public override object Accept (StructuralVisitor visitor)
9339 return visitor.Visit (this);
9343 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9345 public TypeOfMethod (MethodSpec method, Location loc)
9346 : base (method, loc)
9350 protected override Expression DoResolve (ResolveContext ec)
9352 if (member.IsConstructor) {
9353 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9355 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9361 return base.DoResolve (ec);
9364 public override void Emit (EmitContext ec)
9366 ec.Emit (OpCodes.Ldtoken, member);
9369 ec.Emit (OpCodes.Castclass, type);
9372 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9374 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9377 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9379 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9383 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9385 protected readonly T member;
9387 protected TypeOfMember (T member, Location loc)
9389 this.member = member;
9393 public override bool IsSideEffectFree {
9399 public override bool ContainsEmitWithAwait ()
9404 public override Expression CreateExpressionTree (ResolveContext ec)
9406 Arguments args = new Arguments (2);
9407 args.Add (new Argument (this));
9408 args.Add (new Argument (new TypeOf (type, loc)));
9409 return CreateExpressionFactoryCall (ec, "Constant", args);
9412 protected override Expression DoResolve (ResolveContext ec)
9414 eclass = ExprClass.Value;
9418 public override void Emit (EmitContext ec)
9420 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9421 PredefinedMember<MethodSpec> p;
9423 p = GetTypeFromHandleGeneric (ec);
9424 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9426 p = GetTypeFromHandle (ec);
9429 var mi = p.Resolve (loc);
9431 ec.Emit (OpCodes.Call, mi);
9434 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9435 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9438 sealed class TypeOfField : TypeOfMember<FieldSpec>
9440 public TypeOfField (FieldSpec field, Location loc)
9445 protected override Expression DoResolve (ResolveContext ec)
9447 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9451 return base.DoResolve (ec);
9454 public override void Emit (EmitContext ec)
9456 ec.Emit (OpCodes.Ldtoken, member);
9460 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9462 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9465 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9467 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9472 /// Implements the sizeof expression
9474 public class SizeOf : Expression {
9475 readonly Expression texpr;
9476 TypeSpec type_queried;
9478 public SizeOf (Expression queried_type, Location l)
9480 this.texpr = queried_type;
9484 public override bool IsSideEffectFree {
9490 public Expression TypeExpression {
9496 public override bool ContainsEmitWithAwait ()
9501 public override Expression CreateExpressionTree (ResolveContext ec)
9503 Error_PointerInsideExpressionTree (ec);
9507 protected override Expression DoResolve (ResolveContext ec)
9509 type_queried = texpr.ResolveAsType (ec);
9510 if (type_queried == null)
9513 if (type_queried.IsEnum)
9514 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9516 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9518 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9521 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9526 ec.Report.Error (233, loc,
9527 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9528 type_queried.GetSignatureForError ());
9531 type = ec.BuiltinTypes.Int;
9532 eclass = ExprClass.Value;
9536 public override void Emit (EmitContext ec)
9538 ec.Emit (OpCodes.Sizeof, type_queried);
9541 protected override void CloneTo (CloneContext clonectx, Expression t)
9545 public override object Accept (StructuralVisitor visitor)
9547 return visitor.Visit (this);
9552 /// Implements the qualified-alias-member (::) expression.
9554 public class QualifiedAliasMember : MemberAccess
9556 readonly string alias;
9557 public static readonly string GlobalAlias = "global";
9559 public QualifiedAliasMember (string alias, string identifier, Location l)
9560 : base (null, identifier, l)
9565 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9566 : base (null, identifier, targs, l)
9571 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9572 : base (null, identifier, arity, l)
9577 public string Alias {
9583 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9585 if (alias == GlobalAlias)
9586 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9588 int errors = mc.Module.Compiler.Report.Errors;
9589 var expr = mc.LookupNamespaceAlias (alias);
9591 if (errors == mc.Module.Compiler.Report.Errors)
9592 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9600 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9602 expr = CreateExpressionFromAlias (mc);
9606 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9609 protected override Expression DoResolve (ResolveContext rc)
9611 return ResolveAsTypeOrNamespace (rc, false);
9614 public override string GetSignatureForError ()
9617 if (targs != null) {
9618 name = Name + "<" + targs.GetSignatureForError () + ">";
9621 return alias + "::" + name;
9624 public override bool HasConditionalAccess ()
9629 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9631 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9632 rc.Module.Compiler.Report.Error (687, loc,
9633 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9634 GetSignatureForError ());
9639 return DoResolve (rc);
9642 protected override void CloneTo (CloneContext clonectx, Expression t)
9647 public override object Accept (StructuralVisitor visitor)
9649 return visitor.Visit (this);
9654 /// Implements the member access expression
9656 public class MemberAccess : ATypeNameExpression
9658 protected Expression expr;
9660 public MemberAccess (Expression expr, string id)
9661 : base (id, expr.Location)
9666 public MemberAccess (Expression expr, string identifier, Location loc)
9667 : base (identifier, loc)
9672 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9673 : base (identifier, args, loc)
9678 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9679 : base (identifier, arity, loc)
9684 public Expression LeftExpression {
9690 public override Location StartLocation {
9692 return expr == null ? loc : expr.StartLocation;
9696 protected override Expression DoResolve (ResolveContext rc)
9698 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9700 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9705 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9707 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9709 if (e is TypeExpr) {
9710 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9715 e = e.ResolveLValue (rc, rhs);
9720 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9722 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9723 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9725 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9728 public override bool HasConditionalAccess ()
9730 return LeftExpression.HasConditionalAccess ();
9733 public static bool IsValidDotExpression (TypeSpec type)
9735 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9736 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9738 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9741 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9743 var sn = expr as SimpleName;
9744 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9747 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9750 // Resolve expression which does have type set as we need expression type
9751 // with disable flow analysis as we don't know whether left side expression
9752 // is used as variable or type
9754 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9755 expr = expr.Resolve (rc);
9756 } else if (expr is TypeParameterExpr) {
9757 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9761 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9762 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9763 expr = expr.Resolve (rc, flags);
9766 expr = expr.Resolve (rc, flags);
9773 var ns = expr as NamespaceExpression;
9775 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9777 if (retval == null) {
9778 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9783 if (HasTypeArguments)
9784 return new GenericTypeExpr (retval.Type, targs, loc);
9786 targs.Resolve (rc, false);
9792 var cma = this as ConditionalMemberAccess;
9795 TypeSpec expr_type = expr.Type;
9796 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9797 me = expr as MemberExpr;
9799 me.ResolveInstanceExpression (rc, null);
9801 Arguments args = new Arguments (1);
9802 args.Add (new Argument (expr));
9805 return new DynamicConditionalMemberBinder (Name, args, loc);
9807 return new DynamicMemberBinder (Name, args, loc);
9811 if (!IsNullPropagatingValid (expr.Type)) {
9812 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9816 if (expr_type.IsNullableType) {
9817 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9818 expr_type = expr.Type;
9822 if (!IsValidDotExpression (expr_type)) {
9823 Error_OperatorCannotBeApplied (rc, expr_type);
9827 var lookup_arity = Arity;
9828 bool errorMode = false;
9829 Expression member_lookup;
9831 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9832 if (member_lookup == null) {
9834 // Try to look for extension method when member lookup failed
9836 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9837 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9838 if (methods != null) {
9839 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9840 if (HasTypeArguments) {
9841 if (!targs.Resolve (rc, false))
9844 emg.SetTypeArguments (rc, targs);
9848 emg.ConditionalAccess = true;
9850 // TODO: it should really skip the checks bellow
9851 return emg.Resolve (rc);
9857 if (member_lookup == null) {
9858 var dep = expr_type.GetMissingDependencies ();
9860 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9861 } else if (expr is TypeExpr) {
9862 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9864 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9870 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9871 // Leave it to overload resolution to report correct error
9872 } else if (!(member_lookup is TypeExpr)) {
9873 // TODO: rc.SymbolRelatedToPreviousError
9874 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9879 if (member_lookup != null)
9883 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9887 TypeExpr texpr = member_lookup as TypeExpr;
9888 if (texpr != null) {
9889 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9890 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9891 Name, texpr.GetSignatureForError ());
9894 if (!texpr.Type.IsAccessible (rc)) {
9895 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9896 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9900 if (HasTypeArguments) {
9901 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9904 return member_lookup;
9907 me = member_lookup as MemberExpr;
9909 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9914 me.ConditionalAccess = true;
9917 me = me.ResolveMemberAccess (rc, expr, sn);
9920 if (!targs.Resolve (rc, false))
9923 me.SetTypeArguments (rc, targs);
9929 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9931 FullNamedExpression fexpr = expr as FullNamedExpression;
9932 if (fexpr == null) {
9933 expr.ResolveAsType (rc);
9937 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9939 if (expr_resolved == null)
9942 var ns = expr_resolved as NamespaceExpression;
9944 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9946 if (retval == null) {
9947 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9948 } else if (Arity > 0) {
9949 if (HasTypeArguments) {
9950 retval = new GenericTypeExpr (retval.Type, targs, loc);
9951 if (retval.ResolveAsType (rc) == null)
9954 targs.Resolve (rc, allowUnboundTypeArguments);
9956 retval = new GenericOpenTypeExpr (retval.Type, loc);
9963 var tnew_expr = expr_resolved.ResolveAsType (rc);
9964 if (tnew_expr == null)
9967 TypeSpec expr_type = tnew_expr;
9968 if (TypeManager.IsGenericParameter (expr_type)) {
9969 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9970 tnew_expr.GetSignatureForError ());
9974 var qam = this as QualifiedAliasMember;
9976 rc.Module.Compiler.Report.Error (431, loc,
9977 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9982 TypeSpec nested = null;
9983 while (expr_type != null) {
9984 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9985 if (nested == null) {
9986 if (expr_type == tnew_expr) {
9987 Error_IdentifierNotFound (rc, expr_type);
9991 expr_type = tnew_expr;
9992 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9993 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9997 if (nested.IsAccessible (rc))
10001 // Keep looking after inaccessible candidate but only if
10002 // we are not in same context as the definition itself
10004 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10007 expr_type = expr_type.BaseType;
10012 if (HasTypeArguments) {
10013 texpr = new GenericTypeExpr (nested, targs, loc);
10015 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10017 texpr = new GenericOpenTypeExpr (nested, loc);
10019 } else if (expr_resolved is GenericOpenTypeExpr) {
10020 texpr = new GenericOpenTypeExpr (nested, loc);
10022 texpr = new TypeExpression (nested, loc);
10025 if (texpr.ResolveAsType (rc) == null)
10031 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10033 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10035 if (nested != null) {
10036 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10040 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10041 if (any_other_member != null) {
10042 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10046 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10047 Name, expr_type.GetSignatureForError ());
10050 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10052 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10055 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10057 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10058 ec.Report.SymbolRelatedToPreviousError (type);
10060 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10062 // a using directive or an assembly reference
10063 if (cand != null) {
10064 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10066 missing = "an assembly reference";
10069 ec.Report.Error (1061, loc,
10070 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10071 type.GetSignatureForError (), name, missing);
10075 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10078 public override string GetSignatureForError ()
10080 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10083 protected override void CloneTo (CloneContext clonectx, Expression t)
10085 MemberAccess target = (MemberAccess) t;
10087 target.expr = expr.Clone (clonectx);
10090 public override object Accept (StructuralVisitor visitor)
10092 return visitor.Visit (this);
10096 public class ConditionalMemberAccess : MemberAccess
10098 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10099 : base (expr, identifier, args, loc)
10103 public override bool HasConditionalAccess ()
10110 /// Implements checked expressions
10112 public class CheckedExpr : Expression {
10114 public Expression Expr;
10116 public CheckedExpr (Expression e, Location l)
10122 public override bool ContainsEmitWithAwait ()
10124 return Expr.ContainsEmitWithAwait ();
10127 public override Expression CreateExpressionTree (ResolveContext ec)
10129 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10130 return Expr.CreateExpressionTree (ec);
10133 protected override Expression DoResolve (ResolveContext ec)
10135 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10136 Expr = Expr.Resolve (ec);
10141 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10144 eclass = Expr.eclass;
10149 public override void Emit (EmitContext ec)
10151 using (ec.With (EmitContext.Options.CheckedScope, true))
10155 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10157 using (ec.With (EmitContext.Options.CheckedScope, true))
10158 Expr.EmitBranchable (ec, target, on_true);
10161 public override void FlowAnalysis (FlowAnalysisContext fc)
10163 Expr.FlowAnalysis (fc);
10166 public override SLE.Expression MakeExpression (BuilderContext ctx)
10168 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10169 return Expr.MakeExpression (ctx);
10173 protected override void CloneTo (CloneContext clonectx, Expression t)
10175 CheckedExpr target = (CheckedExpr) t;
10177 target.Expr = Expr.Clone (clonectx);
10180 public override object Accept (StructuralVisitor visitor)
10182 return visitor.Visit (this);
10187 /// Implements the unchecked expression
10189 public class UnCheckedExpr : Expression {
10191 public Expression Expr;
10193 public UnCheckedExpr (Expression e, Location l)
10199 public override bool ContainsEmitWithAwait ()
10201 return Expr.ContainsEmitWithAwait ();
10204 public override Expression CreateExpressionTree (ResolveContext ec)
10206 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10207 return Expr.CreateExpressionTree (ec);
10210 protected override Expression DoResolve (ResolveContext ec)
10212 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10213 Expr = Expr.Resolve (ec);
10218 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10221 eclass = Expr.eclass;
10226 public override void Emit (EmitContext ec)
10228 using (ec.With (EmitContext.Options.CheckedScope, false))
10232 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10234 using (ec.With (EmitContext.Options.CheckedScope, false))
10235 Expr.EmitBranchable (ec, target, on_true);
10238 public override void FlowAnalysis (FlowAnalysisContext fc)
10240 Expr.FlowAnalysis (fc);
10243 protected override void CloneTo (CloneContext clonectx, Expression t)
10245 UnCheckedExpr target = (UnCheckedExpr) t;
10247 target.Expr = Expr.Clone (clonectx);
10250 public override object Accept (StructuralVisitor visitor)
10252 return visitor.Visit (this);
10257 /// An Element Access expression.
10259 /// During semantic analysis these are transformed into
10260 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10262 public class ElementAccess : Expression
10264 public Arguments Arguments;
10265 public Expression Expr;
10266 bool conditional_access_receiver;
10268 public ElementAccess (Expression e, Arguments args, Location loc)
10272 this.Arguments = args;
10275 public bool ConditionalAccess { get; set; }
10277 public override Location StartLocation {
10279 return Expr.StartLocation;
10283 public override bool ContainsEmitWithAwait ()
10285 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10289 // We perform some simple tests, and then to "split" the emit and store
10290 // code we create an instance of a different class, and return that.
10292 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10294 if (conditionalAccessReceiver)
10295 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10297 Expr = Expr.Resolve (ec);
10299 if (conditionalAccessReceiver)
10300 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10307 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10308 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10312 if (type.IsArray) {
10313 var aa = new ArrayAccess (this, loc) {
10314 ConditionalAccess = ConditionalAccess,
10317 if (conditionalAccessReceiver)
10318 aa.SetConditionalAccessReceiver ();
10323 if (type.IsPointer)
10324 return Expr.MakePointerAccess (ec, type, Arguments);
10326 FieldExpr fe = Expr as FieldExpr;
10328 var ff = fe.Spec as FixedFieldSpec;
10330 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10334 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10335 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10336 var indexer = new IndexerExpr (indexers, type, this) {
10337 ConditionalAccess = ConditionalAccess
10340 if (conditionalAccessReceiver)
10341 indexer.SetConditionalAccessReceiver ();
10346 Error_CannotApplyIndexing (ec, type, loc);
10351 public override Expression CreateExpressionTree (ResolveContext ec)
10353 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10354 Expr.CreateExpressionTree (ec));
10356 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10359 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10361 if (type != InternalType.ErrorType) {
10362 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10363 type.GetSignatureForError ());
10367 public override bool HasConditionalAccess ()
10369 return ConditionalAccess || Expr.HasConditionalAccess ();
10372 void ResolveConditionalAccessReceiver (ResolveContext rc)
10374 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10375 conditional_access_receiver = true;
10379 protected override Expression DoResolve (ResolveContext rc)
10381 ResolveConditionalAccessReceiver (rc);
10383 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10387 return expr.Resolve (rc);
10390 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10392 var res = CreateAccessExpression (ec, false);
10396 return res.ResolveLValue (ec, rhs);
10399 public override void Emit (EmitContext ec)
10401 throw new Exception ("Should never be reached");
10404 public override void FlowAnalysis (FlowAnalysisContext fc)
10406 Expr.FlowAnalysis (fc);
10408 Arguments.FlowAnalysis (fc);
10411 public override string GetSignatureForError ()
10413 return Expr.GetSignatureForError ();
10416 protected override void CloneTo (CloneContext clonectx, Expression t)
10418 ElementAccess target = (ElementAccess) t;
10420 target.Expr = Expr.Clone (clonectx);
10421 if (Arguments != null)
10422 target.Arguments = Arguments.Clone (clonectx);
10425 public override object Accept (StructuralVisitor visitor)
10427 return visitor.Visit (this);
10432 /// Implements array access
10434 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10436 // Points to our "data" repository
10440 LocalTemporary temp;
10442 bool? has_await_args;
10443 bool conditional_access_receiver;
10445 public ArrayAccess (ElementAccess ea_data, Location l)
10451 public bool ConditionalAccess { get; set; }
10453 public void AddressOf (EmitContext ec, AddressOp mode)
10455 var ac = (ArrayContainer) ea.Expr.Type;
10457 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10458 LoadInstanceAndArguments (ec, false, true);
10461 LoadInstanceAndArguments (ec, false, false);
10463 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10464 ec.Emit (OpCodes.Readonly);
10466 ec.EmitArrayAddress (ac);
10469 public override Expression CreateExpressionTree (ResolveContext ec)
10471 if (ConditionalAccess)
10472 Error_NullShortCircuitInsideExpressionTree (ec);
10474 return ea.CreateExpressionTree (ec);
10477 public override bool ContainsEmitWithAwait ()
10479 return ea.ContainsEmitWithAwait ();
10482 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10484 if (HasConditionalAccess ())
10485 Error_NullPropagatingLValue (ec);
10487 return DoResolve (ec);
10490 protected override Expression DoResolve (ResolveContext ec)
10492 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10494 ea.Arguments.Resolve (ec, out dynamic);
10496 var ac = ea.Expr.Type as ArrayContainer;
10497 int rank = ea.Arguments.Count;
10498 if (ac.Rank != rank) {
10499 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10500 rank.ToString (), ac.Rank.ToString ());
10505 if (type.IsPointer) {
10506 if (ec.CurrentIterator != null) {
10507 UnsafeInsideIteratorError (ec, ea.Location);
10508 } else if (!ec.IsUnsafe) {
10509 UnsafeError (ec, ea.Location);
10513 if (conditional_access_receiver)
10514 type = LiftMemberType (ec, type);
10516 foreach (Argument a in ea.Arguments) {
10517 var na = a as NamedArgument;
10519 ElementAccess.Error_NamedArgument (na, ec.Report);
10521 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10524 eclass = ExprClass.Variable;
10529 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10531 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10534 public override void FlowAnalysis (FlowAnalysisContext fc)
10536 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10538 ea.FlowAnalysis (fc);
10540 if (conditional_access_receiver)
10541 fc.DefiniteAssignment = da;
10544 public override bool HasConditionalAccess ()
10546 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10550 // Load the array arguments into the stack.
10552 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10554 if (prepareAwait) {
10555 ea.Expr = ea.Expr.EmitToField (ec);
10557 var ie = new InstanceEmitter (ea.Expr, false);
10558 ie.Emit (ec, ConditionalAccess);
10560 if (duplicateArguments) {
10561 ec.Emit (OpCodes.Dup);
10563 var copy = new LocalTemporary (ea.Expr.Type);
10569 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10570 if (dup_args != null)
10571 ea.Arguments = dup_args;
10574 public void Emit (EmitContext ec, bool leave_copy)
10577 ec.EmitLoadFromPtr (type);
10579 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10580 LoadInstanceAndArguments (ec, false, true);
10583 if (conditional_access_receiver)
10584 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10586 var ac = (ArrayContainer) ea.Expr.Type;
10587 LoadInstanceAndArguments (ec, false, false);
10588 ec.EmitArrayLoad (ac);
10590 if (conditional_access_receiver)
10591 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10595 ec.Emit (OpCodes.Dup);
10596 temp = new LocalTemporary (this.type);
10601 public override void Emit (EmitContext ec)
10606 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10608 var ac = (ArrayContainer) ea.Expr.Type;
10609 TypeSpec t = source.Type;
10611 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10614 // When we are dealing with a struct, get the address of it to avoid value copy
10615 // Same cannot be done for reference type because array covariance and the
10616 // check in ldelema requires to specify the type of array element stored at the index
10618 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10619 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10621 if (has_await_args.Value) {
10622 if (source.ContainsEmitWithAwait ()) {
10623 source = source.EmitToField (ec);
10624 isCompound = false;
10628 LoadInstanceAndArguments (ec, isCompound, false);
10633 ec.EmitArrayAddress (ac);
10636 ec.Emit (OpCodes.Dup);
10640 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10642 if (has_await_args.Value) {
10643 if (source.ContainsEmitWithAwait ())
10644 source = source.EmitToField (ec);
10646 LoadInstanceAndArguments (ec, false, false);
10653 var lt = ea.Expr as LocalTemporary;
10659 ec.Emit (OpCodes.Dup);
10660 temp = new LocalTemporary (this.type);
10665 ec.EmitStoreFromPtr (t);
10667 ec.EmitArrayStore (ac);
10670 if (temp != null) {
10676 public override Expression EmitToField (EmitContext ec)
10679 // Have to be specialized for arrays to get access to
10680 // underlying element. Instead of another result copy we
10681 // need direct access to element
10685 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10687 ea.Expr = ea.Expr.EmitToField (ec);
10688 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10692 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10694 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10697 public override SLE.Expression MakeExpression (BuilderContext ctx)
10699 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10702 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10704 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10705 return Arguments.MakeExpression (ea.Arguments, ctx);
10709 public void SetConditionalAccessReceiver ()
10711 conditional_access_receiver = true;
10716 // Indexer access expression
10718 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10720 IList<MemberSpec> indexers;
10721 Arguments arguments;
10722 TypeSpec queried_type;
10724 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10725 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10729 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10732 this.indexers = indexers;
10733 this.queried_type = queriedType;
10734 this.InstanceExpression = instance;
10735 this.arguments = args;
10740 protected override Arguments Arguments {
10749 protected override TypeSpec DeclaringType {
10751 return best_candidate.DeclaringType;
10755 public override bool IsInstance {
10761 public override bool IsStatic {
10767 public override string KindName {
10768 get { return "indexer"; }
10771 public override string Name {
10779 public override bool ContainsEmitWithAwait ()
10781 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10784 public override Expression CreateExpressionTree (ResolveContext ec)
10786 if (ConditionalAccess) {
10787 Error_NullShortCircuitInsideExpressionTree (ec);
10790 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10791 InstanceExpression.CreateExpressionTree (ec),
10792 new TypeOfMethod (Getter, loc));
10794 return CreateExpressionFactoryCall (ec, "Call", args);
10797 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10799 LocalTemporary await_source_arg = null;
10802 emitting_compound_assignment = true;
10803 if (source is DynamicExpressionStatement) {
10808 emitting_compound_assignment = false;
10810 if (has_await_arguments) {
10811 await_source_arg = new LocalTemporary (Type);
10812 await_source_arg.Store (ec);
10814 arguments.Add (new Argument (await_source_arg));
10817 temp = await_source_arg;
10820 has_await_arguments = false;
10825 ec.Emit (OpCodes.Dup);
10826 temp = new LocalTemporary (Type);
10832 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10833 source = source.EmitToField (ec);
10835 temp = new LocalTemporary (Type);
10842 arguments.Add (new Argument (source));
10845 var call = new CallEmitter ();
10846 call.InstanceExpression = InstanceExpression;
10847 if (arguments == null)
10848 call.InstanceExpressionOnStack = true;
10850 call.Emit (ec, Setter, arguments, loc);
10852 if (temp != null) {
10855 } else if (leave_copy) {
10859 if (await_source_arg != null) {
10860 await_source_arg.Release (ec);
10864 public override void FlowAnalysis (FlowAnalysisContext fc)
10866 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10868 base.FlowAnalysis (fc);
10869 arguments.FlowAnalysis (fc);
10871 if (conditional_access_receiver)
10872 fc.DefiniteAssignment = da;
10875 public override string GetSignatureForError ()
10877 return best_candidate.GetSignatureForError ();
10880 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10883 throw new NotSupportedException ();
10885 var value = new[] { source.MakeExpression (ctx) };
10886 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10887 return SLE.Expression.Block (
10888 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10893 public override SLE.Expression MakeExpression (BuilderContext ctx)
10896 return base.MakeExpression (ctx);
10898 var args = Arguments.MakeExpression (arguments, ctx);
10899 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10903 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10905 if (best_candidate != null)
10908 eclass = ExprClass.IndexerAccess;
10911 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10912 arguments.Resolve (rc, out dynamic);
10915 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10918 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10919 res.BaseMembersProvider = this;
10920 res.InstanceQualifier = this;
10922 // TODO: Do I need 2 argument sets?
10923 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10924 if (best_candidate != null)
10925 type = res.BestCandidateReturnType;
10926 else if (!res.BestCandidateIsDynamic)
10931 // It has dynamic arguments
10934 Arguments args = new Arguments (arguments.Count + 1);
10936 rc.Report.Error (1972, loc,
10937 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10939 args.Add (new Argument (InstanceExpression));
10941 args.AddRange (arguments);
10943 best_candidate = null;
10944 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10948 // Try to avoid resolving left expression again
10950 if (right_side != null)
10951 ResolveInstanceExpression (rc, right_side);
10956 protected override void CloneTo (CloneContext clonectx, Expression t)
10958 IndexerExpr target = (IndexerExpr) t;
10960 if (arguments != null)
10961 target.arguments = arguments.Clone (clonectx);
10964 public void SetConditionalAccessReceiver ()
10966 conditional_access_receiver = true;
10969 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10971 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10974 #region IBaseMembersProvider Members
10976 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
10978 var baseType = type.BaseType;
10979 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10981 if (members == null && !type.IsInterface) {
10982 var tps = queried_type as TypeParameterSpec;
10984 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
10990 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10992 if (queried_type == member.DeclaringType)
10995 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10996 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10999 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11008 // A base access expression
11010 public class BaseThis : This
11012 public BaseThis (Location loc)
11017 public BaseThis (TypeSpec type, Location loc)
11021 eclass = ExprClass.Variable;
11026 public override string Name {
11034 public override Expression CreateExpressionTree (ResolveContext ec)
11036 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11037 return base.CreateExpressionTree (ec);
11040 public override void Emit (EmitContext ec)
11044 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11045 var context_type = ec.CurrentType;
11046 ec.Emit (OpCodes.Ldobj, context_type);
11047 ec.Emit (OpCodes.Box, context_type);
11051 protected override void Error_ThisNotAvailable (ResolveContext ec)
11054 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11056 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11060 public override void ResolveBase (ResolveContext ec)
11062 base.ResolveBase (ec);
11063 type = ec.CurrentType.BaseType;
11066 public override object Accept (StructuralVisitor visitor)
11068 return visitor.Visit (this);
11073 /// This class exists solely to pass the Type around and to be a dummy
11074 /// that can be passed to the conversion functions (this is used by
11075 /// foreach implementation to typecast the object return value from
11076 /// get_Current into the proper type. All code has been generated and
11077 /// we only care about the side effect conversions to be performed
11079 /// This is also now used as a placeholder where a no-action expression
11080 /// is needed (the `New' class).
11082 public class EmptyExpression : Expression
11084 sealed class OutAccessExpression : EmptyExpression
11086 public OutAccessExpression (TypeSpec t)
11091 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11093 rc.Report.Error (206, right_side.Location,
11094 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11100 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11101 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11102 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11103 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11104 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11105 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11106 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11107 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11109 public EmptyExpression (TypeSpec t)
11112 eclass = ExprClass.Value;
11113 loc = Location.Null;
11116 protected override void CloneTo (CloneContext clonectx, Expression target)
11120 public override bool ContainsEmitWithAwait ()
11125 public override Expression CreateExpressionTree (ResolveContext ec)
11127 throw new NotSupportedException ("ET");
11130 protected override Expression DoResolve (ResolveContext ec)
11135 public override void Emit (EmitContext ec)
11137 // nothing, as we only exist to not do anything.
11140 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11144 public override void EmitSideEffect (EmitContext ec)
11148 public override object Accept (StructuralVisitor visitor)
11150 return visitor.Visit (this);
11154 sealed class EmptyAwaitExpression : EmptyExpression
11156 public EmptyAwaitExpression (TypeSpec type)
11161 public override bool ContainsEmitWithAwait ()
11168 // Empty statement expression
11170 public sealed class EmptyExpressionStatement : ExpressionStatement
11172 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11174 private EmptyExpressionStatement ()
11176 loc = Location.Null;
11179 public override bool ContainsEmitWithAwait ()
11184 public override Expression CreateExpressionTree (ResolveContext ec)
11189 public override void EmitStatement (EmitContext ec)
11194 protected override Expression DoResolve (ResolveContext ec)
11196 eclass = ExprClass.Value;
11197 type = ec.BuiltinTypes.Object;
11201 public override void Emit (EmitContext ec)
11206 public override object Accept (StructuralVisitor visitor)
11208 return visitor.Visit (this);
11212 public class ErrorExpression : EmptyExpression
11214 public static readonly ErrorExpression Instance = new ErrorExpression ();
11216 private ErrorExpression ()
11217 : base (InternalType.ErrorType)
11221 public override Expression CreateExpressionTree (ResolveContext ec)
11226 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11231 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11235 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11239 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11243 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11247 public override object Accept (StructuralVisitor visitor)
11249 return visitor.Visit (this);
11253 public class UserCast : Expression {
11257 public UserCast (MethodSpec method, Expression source, Location l)
11259 if (source == null)
11260 throw new ArgumentNullException ("source");
11262 this.method = method;
11263 this.source = source;
11264 type = method.ReturnType;
11268 public Expression Source {
11277 public override bool ContainsEmitWithAwait ()
11279 return source.ContainsEmitWithAwait ();
11282 public override Expression CreateExpressionTree (ResolveContext ec)
11284 Arguments args = new Arguments (3);
11285 args.Add (new Argument (source.CreateExpressionTree (ec)));
11286 args.Add (new Argument (new TypeOf (type, loc)));
11287 args.Add (new Argument (new TypeOfMethod (method, loc)));
11288 return CreateExpressionFactoryCall (ec, "Convert", args);
11291 protected override Expression DoResolve (ResolveContext ec)
11293 method.CheckObsoleteness (ec, source.Location);
11295 eclass = ExprClass.Value;
11299 public override void Emit (EmitContext ec)
11302 ec.MarkCallEntry (loc);
11303 ec.Emit (OpCodes.Call, method);
11306 public override void FlowAnalysis (FlowAnalysisContext fc)
11308 source.FlowAnalysis (fc);
11311 public override string GetSignatureForError ()
11313 return TypeManager.CSharpSignature (method);
11316 public override SLE.Expression MakeExpression (BuilderContext ctx)
11319 return base.MakeExpression (ctx);
11321 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11327 // Holds additional type specifiers like ?, *, []
11329 public class ComposedTypeSpecifier
11331 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11333 public readonly int Dimension;
11334 public readonly Location Location;
11336 public ComposedTypeSpecifier (int specifier, Location loc)
11338 this.Dimension = specifier;
11339 this.Location = loc;
11343 public bool IsNullable {
11345 return Dimension == -1;
11349 public bool IsPointer {
11351 return Dimension == -2;
11355 public ComposedTypeSpecifier Next { get; set; }
11359 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11361 return new ComposedTypeSpecifier (dimension, loc);
11364 public static ComposedTypeSpecifier CreateNullable (Location loc)
11366 return new ComposedTypeSpecifier (-1, loc);
11369 public static ComposedTypeSpecifier CreatePointer (Location loc)
11371 return new ComposedTypeSpecifier (-2, loc);
11374 public string GetSignatureForError ()
11379 ArrayContainer.GetPostfixSignature (Dimension);
11381 return Next != null ? s + Next.GetSignatureForError () : s;
11386 // This class is used to "construct" the type during a typecast
11387 // operation. Since the Type.GetType class in .NET can parse
11388 // the type specification, we just use this to construct the type
11389 // one bit at a time.
11391 public class ComposedCast : TypeExpr {
11392 FullNamedExpression left;
11393 ComposedTypeSpecifier spec;
11395 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11398 throw new ArgumentNullException ("spec");
11402 this.loc = left.Location;
11405 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11407 type = left.ResolveAsType (ec);
11411 eclass = ExprClass.Type;
11413 var single_spec = spec;
11415 if (single_spec.IsNullable) {
11416 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11420 single_spec = single_spec.Next;
11421 } else if (single_spec.IsPointer) {
11423 // Declared fields cannot have unmanaged check done before all types are defined
11425 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11428 var rc = ec as ResolveContext;
11429 if (rc?.CurrentIterator != null) {
11430 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11431 } else if (!ec.IsUnsafe) {
11432 UnsafeError (ec.Module.Compiler.Report, loc);
11436 type = PointerContainer.MakeType (ec.Module, type);
11437 single_spec = single_spec.Next;
11438 } while (single_spec != null && single_spec.IsPointer);
11441 if (single_spec != null && single_spec.Dimension > 0) {
11442 if (type.IsSpecialRuntimeType) {
11443 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11444 } else if (type.IsStatic) {
11445 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11446 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11447 type.GetSignatureForError ());
11449 MakeArray (ec.Module, single_spec);
11456 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11458 if (spec.Next != null)
11459 MakeArray (module, spec.Next);
11461 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11464 public override string GetSignatureForError ()
11466 return left.GetSignatureForError () + spec.GetSignatureForError ();
11469 public override object Accept (StructuralVisitor visitor)
11471 return visitor.Visit (this);
11475 class FixedBufferPtr : Expression
11477 readonly Expression array;
11479 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11481 this.type = array_type;
11482 this.array = array;
11486 public override bool ContainsEmitWithAwait ()
11488 throw new NotImplementedException ();
11491 public override Expression CreateExpressionTree (ResolveContext ec)
11493 Error_PointerInsideExpressionTree (ec);
11497 public override void Emit(EmitContext ec)
11502 protected override Expression DoResolve (ResolveContext ec)
11504 type = PointerContainer.MakeType (ec.Module, type);
11505 eclass = ExprClass.Value;
11512 // This class is used to represent the address of an array, used
11513 // only by the Fixed statement, this generates "&a [0]" construct
11514 // for fixed (char *pa = a)
11516 class ArrayPtr : FixedBufferPtr
11518 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11519 base (array, array_type, l)
11523 public override void Emit (EmitContext ec)
11528 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11533 // Encapsulates a conversion rules required for array indexes
11535 public class ArrayIndexCast : TypeCast
11537 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11538 : base (expr, returnType)
11540 if (expr.Type == returnType) // int -> int
11541 throw new ArgumentException ("unnecessary array index conversion");
11544 public override Expression CreateExpressionTree (ResolveContext ec)
11546 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11547 return base.CreateExpressionTree (ec);
11551 public override void Emit (EmitContext ec)
11555 switch (child.Type.BuiltinType) {
11556 case BuiltinTypeSpec.Type.UInt:
11557 ec.Emit (OpCodes.Conv_U);
11559 case BuiltinTypeSpec.Type.Long:
11560 ec.Emit (OpCodes.Conv_Ovf_I);
11562 case BuiltinTypeSpec.Type.ULong:
11563 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11566 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11572 // Implements the `stackalloc' keyword
11574 public class StackAlloc : Expression {
11579 public StackAlloc (Expression type, Expression count, Location l)
11582 this.count = count;
11586 public Expression TypeExpression {
11592 public Expression CountExpression {
11598 public override bool ContainsEmitWithAwait ()
11603 public override Expression CreateExpressionTree (ResolveContext ec)
11605 throw new NotSupportedException ("ET");
11608 protected override Expression DoResolve (ResolveContext ec)
11610 count = count.Resolve (ec);
11614 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11615 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11620 Constant c = count as Constant;
11621 if (c != null && c.IsNegative) {
11622 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11625 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11626 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11629 otype = texpr.ResolveAsType (ec);
11633 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11636 type = PointerContainer.MakeType (ec.Module, otype);
11637 eclass = ExprClass.Value;
11642 public override void Emit (EmitContext ec)
11644 int size = BuiltinTypeSpec.GetSize (otype);
11649 ec.Emit (OpCodes.Sizeof, otype);
11653 ec.Emit (OpCodes.Mul_Ovf_Un);
11654 ec.Emit (OpCodes.Localloc);
11657 protected override void CloneTo (CloneContext clonectx, Expression t)
11659 StackAlloc target = (StackAlloc) t;
11660 target.count = count.Clone (clonectx);
11661 target.texpr = texpr.Clone (clonectx);
11664 public override object Accept (StructuralVisitor visitor)
11666 return visitor.Visit (this);
11671 // An object initializer expression
11673 public class ElementInitializer : Assign
11675 public readonly string Name;
11677 public ElementInitializer (string name, Expression initializer, Location loc)
11678 : base (null, initializer, loc)
11683 public bool IsDictionaryInitializer {
11685 return Name == null;
11689 protected override void CloneTo (CloneContext clonectx, Expression t)
11691 ElementInitializer target = (ElementInitializer) t;
11692 target.source = source.Clone (clonectx);
11695 public override Expression CreateExpressionTree (ResolveContext ec)
11697 Arguments args = new Arguments (2);
11698 FieldExpr fe = target as FieldExpr;
11700 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11702 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11705 Expression arg_expr;
11706 var cinit = source as CollectionOrObjectInitializers;
11707 if (cinit == null) {
11709 arg_expr = source.CreateExpressionTree (ec);
11711 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11712 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11715 args.Add (new Argument (arg_expr));
11716 return CreateExpressionFactoryCall (ec, mname, args);
11719 protected override Expression DoResolve (ResolveContext ec)
11721 if (source == null)
11722 return EmptyExpressionStatement.Instance;
11724 if (!ResolveElement (ec))
11727 if (source is CollectionOrObjectInitializers) {
11728 target = target.Resolve (ec);
11729 if (target == null)
11732 Expression previous = ec.CurrentInitializerVariable;
11733 ec.CurrentInitializerVariable = target;
11734 source = source.Resolve (ec);
11735 ec.CurrentInitializerVariable = previous;
11736 if (source == null)
11739 eclass = source.eclass;
11740 type = source.Type;
11745 return base.DoResolve (ec);
11748 public override void EmitStatement (EmitContext ec)
11750 if (source is CollectionOrObjectInitializers)
11753 base.EmitStatement (ec);
11756 protected virtual bool ResolveElement (ResolveContext rc)
11758 var t = rc.CurrentInitializerVariable.Type;
11759 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11760 Arguments args = new Arguments (1);
11761 args.Add (new Argument (rc.CurrentInitializerVariable));
11762 target = new DynamicMemberBinder (Name, args, loc);
11764 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11765 if (member == null) {
11766 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11768 if (member != null) {
11769 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11770 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11775 if (member == null) {
11776 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11780 var me = member as MemberExpr;
11781 if (me is EventExpr) {
11782 me = me.ResolveMemberAccess (rc, null, null);
11783 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11784 rc.Report.Error (1913, loc,
11785 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11786 member.GetSignatureForError ());
11792 rc.Report.Error (1914, loc,
11793 "Static field or property `{0}' cannot be assigned in an object initializer",
11794 me.GetSignatureForError ());
11798 me.InstanceExpression = rc.CurrentInitializerVariable;
11806 // A collection initializer expression
11808 class CollectionElementInitializer : Invocation
11810 public class ElementInitializerArgument : Argument
11812 public ElementInitializerArgument (Expression e)
11818 sealed class AddMemberAccess : MemberAccess
11820 public AddMemberAccess (Expression expr, Location loc)
11821 : base (expr, "Add", loc)
11825 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11827 if (TypeManager.HasElementType (type))
11830 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11834 public CollectionElementInitializer (Expression argument)
11835 : base (null, new Arguments (1))
11837 base.arguments.Add (new ElementInitializerArgument (argument));
11838 this.loc = argument.Location;
11841 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11842 : base (null, new Arguments (arguments.Count))
11844 foreach (Expression e in arguments)
11845 base.arguments.Add (new ElementInitializerArgument (e));
11850 public CollectionElementInitializer (Location loc)
11851 : base (null, null)
11856 public override Expression CreateExpressionTree (ResolveContext ec)
11858 Arguments args = new Arguments (2);
11859 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11861 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11862 foreach (Argument a in arguments) {
11863 if (a.ArgType == Argument.AType.ExtensionType) {
11864 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11867 expr_initializers.Add (a.CreateExpressionTree (ec));
11870 args.Add (new Argument (new ArrayCreation (
11871 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11872 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11875 protected override void CloneTo (CloneContext clonectx, Expression t)
11877 CollectionElementInitializer target = (CollectionElementInitializer) t;
11878 if (arguments != null)
11879 target.arguments = arguments.Clone (clonectx);
11882 protected override Expression DoResolve (ResolveContext ec)
11884 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11886 return base.DoResolve (ec);
11890 class DictionaryElementInitializer : ElementInitializer
11892 readonly Arguments args;
11894 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11895 : base (null, initializer, loc)
11897 this.args = arguments;
11900 public override Expression CreateExpressionTree (ResolveContext ec)
11902 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11906 protected override bool ResolveElement (ResolveContext rc)
11908 var init = rc.CurrentInitializerVariable;
11909 var type = init.Type;
11911 if (type.IsArray) {
11912 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11916 if (type.IsPointer) {
11917 target = init.MakePointerAccess (rc, type, args);
11921 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11922 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11923 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11927 target = new IndexerExpr (indexers, type, init, args, loc);
11933 // A block of object or collection initializers
11935 public class CollectionOrObjectInitializers : ExpressionStatement
11937 IList<Expression> initializers;
11938 bool is_collection_initialization;
11940 public CollectionOrObjectInitializers (Location loc)
11941 : this (new Expression[0], loc)
11945 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11947 this.initializers = initializers;
11951 public IList<Expression> Initializers {
11953 return initializers;
11957 public bool IsEmpty {
11959 return initializers.Count == 0;
11963 public bool IsCollectionInitializer {
11965 return is_collection_initialization;
11969 protected override void CloneTo (CloneContext clonectx, Expression target)
11971 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11973 t.initializers = new List<Expression> (initializers.Count);
11974 foreach (var e in initializers)
11975 t.initializers.Add (e.Clone (clonectx));
11978 public override bool ContainsEmitWithAwait ()
11980 foreach (var e in initializers) {
11981 if (e.ContainsEmitWithAwait ())
11988 public override Expression CreateExpressionTree (ResolveContext ec)
11990 return CreateExpressionTree (ec, false);
11993 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11995 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11996 foreach (Expression e in initializers) {
11997 Expression expr = e.CreateExpressionTree (ec);
11999 expr_initializers.Add (expr);
12003 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12005 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12008 protected override Expression DoResolve (ResolveContext ec)
12010 List<string> element_names = null;
12011 for (int i = 0; i < initializers.Count; ++i) {
12012 Expression initializer = initializers [i];
12013 ElementInitializer element_initializer = initializer as ElementInitializer;
12016 if (element_initializer != null) {
12017 element_names = new List<string> (initializers.Count);
12018 if (!element_initializer.IsDictionaryInitializer)
12019 element_names.Add (element_initializer.Name);
12020 } else if (initializer is CompletingExpression) {
12021 initializer.Resolve (ec);
12022 throw new InternalErrorException ("This line should never be reached");
12024 var t = ec.CurrentInitializerVariable.Type;
12025 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12026 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12027 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12028 "object initializer because type `{1}' does not implement `{2}' interface",
12029 ec.CurrentInitializerVariable.GetSignatureForError (),
12030 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12031 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12034 is_collection_initialization = true;
12037 if (is_collection_initialization != (element_initializer == null)) {
12038 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12039 is_collection_initialization ? "collection initializer" : "object initializer");
12043 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12044 if (element_names.Contains (element_initializer.Name)) {
12045 ec.Report.Error (1912, element_initializer.Location,
12046 "An object initializer includes more than one member `{0}' initialization",
12047 element_initializer.Name);
12049 element_names.Add (element_initializer.Name);
12054 Expression e = initializer.Resolve (ec);
12055 if (e == EmptyExpressionStatement.Instance)
12056 initializers.RemoveAt (i--);
12058 initializers [i] = e;
12061 type = ec.CurrentInitializerVariable.Type;
12062 if (is_collection_initialization) {
12063 if (TypeManager.HasElementType (type)) {
12064 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12065 type.GetSignatureForError ());
12069 eclass = ExprClass.Variable;
12073 public override void Emit (EmitContext ec)
12075 EmitStatement (ec);
12078 public override void EmitStatement (EmitContext ec)
12080 foreach (ExpressionStatement e in initializers) {
12081 // TODO: need location region
12082 ec.Mark (e.Location);
12083 e.EmitStatement (ec);
12087 public override void FlowAnalysis (FlowAnalysisContext fc)
12089 foreach (var initializer in initializers) {
12090 if (initializer != null)
12091 initializer.FlowAnalysis (fc);
12097 // New expression with element/object initializers
12099 public class NewInitialize : New
12102 // This class serves as a proxy for variable initializer target instances.
12103 // A real variable is assigned later when we resolve left side of an
12106 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12108 NewInitialize new_instance;
12110 public InitializerTargetExpression (NewInitialize newInstance)
12112 this.type = newInstance.type;
12113 this.loc = newInstance.loc;
12114 this.eclass = newInstance.eclass;
12115 this.new_instance = newInstance;
12118 public override bool ContainsEmitWithAwait ()
12123 public override Expression CreateExpressionTree (ResolveContext ec)
12125 // Should not be reached
12126 throw new NotSupportedException ("ET");
12129 protected override Expression DoResolve (ResolveContext ec)
12134 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12139 public override void Emit (EmitContext ec)
12141 Expression e = (Expression) new_instance.instance;
12145 public override Expression EmitToField (EmitContext ec)
12147 return (Expression) new_instance.instance;
12150 #region IMemoryLocation Members
12152 public void AddressOf (EmitContext ec, AddressOp mode)
12154 new_instance.instance.AddressOf (ec, mode);
12160 CollectionOrObjectInitializers initializers;
12161 IMemoryLocation instance;
12162 DynamicExpressionStatement dynamic;
12164 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12165 : base (requested_type, arguments, l)
12167 this.initializers = initializers;
12170 public CollectionOrObjectInitializers Initializers {
12172 return initializers;
12176 protected override void CloneTo (CloneContext clonectx, Expression t)
12178 base.CloneTo (clonectx, t);
12180 NewInitialize target = (NewInitialize) t;
12181 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12184 public override bool ContainsEmitWithAwait ()
12186 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12189 public override Expression CreateExpressionTree (ResolveContext ec)
12191 Arguments args = new Arguments (2);
12192 args.Add (new Argument (base.CreateExpressionTree (ec)));
12193 if (!initializers.IsEmpty)
12194 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12196 return CreateExpressionFactoryCall (ec,
12197 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12201 protected override Expression DoResolve (ResolveContext rc)
12203 Expression e = base.DoResolve (rc);
12207 if (type.IsDelegate) {
12208 rc.Report.Error (1958, Initializers.Location,
12209 "Object and collection initializers cannot be used to instantiate a delegate");
12212 Expression previous = rc.CurrentInitializerVariable;
12213 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12214 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12215 initializers.Resolve (rc);
12217 rc.CurrentInitializerVariable = previous;
12219 dynamic = e as DynamicExpressionStatement;
12220 if (dynamic != null)
12226 public override void Emit (EmitContext ec)
12228 if (!CanEmitOptimizedLocalTarget (ec)) {
12229 var fe = ec.GetTemporaryField (type);
12231 if (!Emit (ec, fe))
12240 public override bool Emit (EmitContext ec, IMemoryLocation target)
12243 // Expression is initialized into temporary target then moved
12244 // to real one for atomicity
12246 IMemoryLocation temp_target = target;
12248 LocalTemporary temp = null;
12249 bool by_ref = false;
12250 if (!initializers.IsEmpty) {
12251 temp_target = target as LocalTemporary;
12252 if (temp_target == null)
12253 temp_target = target as StackFieldExpr;
12255 if (temp_target == null) {
12256 var vr = target as VariableReference;
12257 if (vr != null && vr.IsRef) {
12263 if (temp_target == null)
12264 temp_target = temp = new LocalTemporary (type);
12267 bool left_on_stack;
12268 if (dynamic != null) {
12270 left_on_stack = true;
12272 left_on_stack = base.Emit (ec, temp_target);
12275 if (initializers.IsEmpty)
12276 return left_on_stack;
12278 StackFieldExpr sf = null;
12280 // Move a new instance (reference-type) to local temporary variable
12281 if (left_on_stack) {
12283 temp_target = temp = new LocalTemporary (type);
12289 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12291 throw new NotImplementedException ();
12293 sf = ec.GetTemporaryField (type);
12294 sf.AutomaticallyReuse = false;
12295 sf.EmitAssign (ec, temp, false, false);
12298 left_on_stack = false;
12302 instance = temp_target;
12304 initializers.Emit (ec);
12306 ((Expression)temp_target).Emit (ec);
12312 sf.PrepareCleanup (ec);
12317 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12319 return !(method == null && TypeSpec.IsValueType (type) &&
12320 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12321 initializers.ContainsEmitWithAwait ());
12324 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12326 instance = base.EmitAddressOf (ec, Mode);
12328 if (!initializers.IsEmpty)
12329 initializers.Emit (ec);
12334 public override void FlowAnalysis (FlowAnalysisContext fc)
12336 base.FlowAnalysis (fc);
12337 initializers.FlowAnalysis (fc);
12340 public override object Accept (StructuralVisitor visitor)
12342 return visitor.Visit (this);
12346 public class NewAnonymousType : New
12348 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12350 List<AnonymousTypeParameter> parameters;
12351 readonly TypeContainer parent;
12352 AnonymousTypeClass anonymous_type;
12354 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12355 : base (null, null, loc)
12357 this.parameters = parameters;
12358 this.parent = parent;
12361 public List<AnonymousTypeParameter> Parameters {
12363 return this.parameters;
12367 protected override void CloneTo (CloneContext clonectx, Expression target)
12369 if (parameters == null)
12372 NewAnonymousType t = (NewAnonymousType) target;
12373 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12374 foreach (AnonymousTypeParameter atp in parameters)
12375 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12378 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12380 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12384 type = AnonymousTypeClass.Create (parent, parameters, loc);
12388 int errors = ec.Report.Errors;
12389 type.CreateContainer ();
12390 type.DefineContainer ();
12391 type.ExpandBaseInterfaces ();
12393 if ((ec.Report.Errors - errors) == 0) {
12394 parent.Module.AddAnonymousType (type);
12395 type.PrepareEmit ();
12401 public override Expression CreateExpressionTree (ResolveContext ec)
12403 if (parameters == null)
12404 return base.CreateExpressionTree (ec);
12406 var init = new ArrayInitializer (parameters.Count, loc);
12407 foreach (var m in anonymous_type.Members) {
12408 var p = m as Property;
12410 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12413 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12414 foreach (Argument a in arguments)
12415 ctor_args.Add (a.CreateExpressionTree (ec));
12417 Arguments args = new Arguments (3);
12418 args.Add (new Argument (new TypeOfMethod (method, loc)));
12419 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12420 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12422 return CreateExpressionFactoryCall (ec, "New", args);
12425 protected override Expression DoResolve (ResolveContext ec)
12427 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12428 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12432 if (parameters == null) {
12433 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12434 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12435 return base.DoResolve (ec);
12438 bool error = false;
12439 arguments = new Arguments (parameters.Count);
12440 var t_args = new TypeSpec [parameters.Count];
12441 for (int i = 0; i < parameters.Count; ++i) {
12442 Expression e = parameters [i].Resolve (ec);
12448 arguments.Add (new Argument (e));
12449 t_args [i] = e.Type;
12455 anonymous_type = CreateAnonymousType (ec, parameters);
12456 if (anonymous_type == null)
12459 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12460 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12461 eclass = ExprClass.Value;
12465 public override object Accept (StructuralVisitor visitor)
12467 return visitor.Visit (this);
12471 public class AnonymousTypeParameter : ShimExpression
12473 public readonly string Name;
12475 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12476 : base (initializer)
12482 public AnonymousTypeParameter (Parameter parameter)
12483 : base (new SimpleName (parameter.Name, parameter.Location))
12485 this.Name = parameter.Name;
12486 this.loc = parameter.Location;
12489 public override bool Equals (object o)
12491 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12492 return other != null && Name == other.Name;
12495 public override int GetHashCode ()
12497 return Name.GetHashCode ();
12500 protected override Expression DoResolve (ResolveContext ec)
12502 Expression e = expr.Resolve (ec);
12506 if (e.eclass == ExprClass.MethodGroup) {
12507 Error_InvalidInitializer (ec, e.ExprClassName);
12512 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12513 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12520 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12522 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12523 Name, initializer);
12527 public class CatchFilterExpression : BooleanExpression
12529 public CatchFilterExpression (Expression expr, Location loc)
12536 public class InterpolatedString : Expression
12538 readonly StringLiteral start, end;
12539 List<Expression> interpolations;
12540 Arguments arguments;
12542 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12544 this.start = start;
12546 this.interpolations = interpolations;
12547 loc = start.Location;
12550 protected override void CloneTo (CloneContext clonectx, Expression t)
12552 InterpolatedString target = (InterpolatedString) t;
12554 if (interpolations != null) {
12555 target.interpolations = new List<Expression> ();
12556 foreach (var interpolation in interpolations) {
12557 target.interpolations.Add (interpolation.Clone (clonectx));
12562 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12564 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12565 if (factory == null)
12568 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12569 var res = new Invocation (ma, arguments).Resolve (rc);
12570 if (res != null && res.Type != type)
12571 res = Convert.ExplicitConversion (rc, res, type, loc);
12576 public override bool ContainsEmitWithAwait ()
12578 if (interpolations == null)
12581 foreach (var expr in interpolations) {
12582 if (expr.ContainsEmitWithAwait ())
12589 public override Expression CreateExpressionTree (ResolveContext rc)
12591 var best = ResolveBestFormatOverload (rc);
12595 Expression instance = new NullLiteral (loc);
12596 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12597 return CreateExpressionFactoryCall (rc, "Call", args);
12600 protected override Expression DoResolve (ResolveContext rc)
12604 if (interpolations == null) {
12606 arguments = new Arguments (1);
12608 arguments = new Arguments (interpolations.Count);
12610 var sb = new StringBuilder (start.Value);
12611 for (int i = 0; i < interpolations.Count; ++i) {
12613 sb.Append ('{').Append (i / 2);
12614 var isi = (InterpolatedStringInsert)interpolations [i];
12615 if (isi.Alignment != null) {
12617 var value = isi.ResolveAligment (rc);
12619 sb.Append (value.Value);
12622 if (isi.Format != null) {
12624 sb.Append (isi.Format);
12628 arguments.Add (new Argument (isi.Resolve (rc)));
12630 sb.Append (((StringLiteral)interpolations [i]).Value);
12634 sb.Append (end.Value);
12635 str = sb.ToString ();
12638 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12640 eclass = ExprClass.Value;
12641 type = rc.BuiltinTypes.String;
12645 public override void Emit (EmitContext ec)
12647 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12648 if (interpolations == null) {
12649 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12650 if (str != start.Value)
12651 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12658 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12662 var ca = new CallEmitter ();
12663 ca.Emit (ec, best, arguments, loc);
12666 public override void FlowAnalysis (FlowAnalysisContext fc)
12668 if (interpolations != null) {
12669 foreach (var expr in interpolations) {
12670 expr.FlowAnalysis (fc);
12675 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12677 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12678 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12679 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12683 public class InterpolatedStringInsert : CompositeExpression
12685 public InterpolatedStringInsert (Expression expr)
12690 public Expression Alignment { get; set; }
12691 public string Format { get; set; }
12693 protected override void CloneTo (CloneContext clonectx, Expression t)
12695 var target = (InterpolatedStringInsert)t;
12696 target.expr = expr.Clone (clonectx);
12697 if (Alignment != null)
12698 target.Alignment = Alignment.Clone (clonectx);
12701 protected override Expression DoResolve (ResolveContext rc)
12703 var expr = base.DoResolve (rc);
12708 // For better error reporting, assumes the built-in implementation uses object
12711 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12714 public override void FlowAnalysis (FlowAnalysisContext fc)
12716 Child.FlowAnalysis (fc);
12719 public int? ResolveAligment (ResolveContext rc)
12721 var c = Alignment.ResolveLabelConstant (rc);
12725 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12729 var value = (int) c.GetValueAsLong ();
12730 if (value > 32767 || value < -32767) {
12731 rc.Report.Warning (8094, 1, Alignment.Location,
12732 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");