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 if (target != null && is_value_type && (vr != null || method == null)) {
7574 target.AddressOf (ec, AddressOp.Store);
7575 } else if (vr != null && vr.IsRef) {
7579 if (arguments != null) {
7580 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7581 arguments = arguments.Emit (ec, false, true);
7583 arguments.Emit (ec);
7586 if (is_value_type) {
7587 if (method == null) {
7588 ec.Emit (OpCodes.Initobj, type);
7593 ec.MarkCallEntry (loc);
7594 ec.Emit (OpCodes.Call, method);
7599 if (type is TypeParameterSpec) {
7600 DoEmitTypeParameter (ec);
7604 ec.MarkCallEntry (loc);
7605 ec.Emit (OpCodes.Newobj, method);
7609 public override void Emit (EmitContext ec)
7611 LocalTemporary v = null;
7612 if (method == null && type.IsStructOrEnum) {
7613 // TODO: Use temporary variable from pool
7614 v = new LocalTemporary (type);
7621 public override void EmitStatement (EmitContext ec)
7623 LocalTemporary v = null;
7624 if (method == null && TypeSpec.IsValueType (type)) {
7625 // TODO: Use temporary variable from pool
7626 v = new LocalTemporary (type);
7630 ec.Emit (OpCodes.Pop);
7633 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7638 public override void FlowAnalysis (FlowAnalysisContext fc)
7640 if (arguments != null)
7641 arguments.FlowAnalysis (fc);
7644 public void AddressOf (EmitContext ec, AddressOp mode)
7646 EmitAddressOf (ec, mode);
7649 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7651 LocalTemporary value_target = new LocalTemporary (type);
7653 if (type is TypeParameterSpec) {
7654 DoEmitTypeParameter (ec);
7655 value_target.Store (ec);
7656 value_target.AddressOf (ec, mode);
7657 return value_target;
7660 value_target.AddressOf (ec, AddressOp.Store);
7662 if (method == null) {
7663 ec.Emit (OpCodes.Initobj, type);
7665 if (arguments != null)
7666 arguments.Emit (ec);
7668 ec.Emit (OpCodes.Call, method);
7671 value_target.AddressOf (ec, mode);
7672 return value_target;
7675 protected override void CloneTo (CloneContext clonectx, Expression t)
7677 New target = (New) t;
7679 target.RequestedType = RequestedType.Clone (clonectx);
7680 if (arguments != null){
7681 target.arguments = arguments.Clone (clonectx);
7685 public override SLE.Expression MakeExpression (BuilderContext ctx)
7688 return base.MakeExpression (ctx);
7690 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7694 public override object Accept (StructuralVisitor visitor)
7696 return visitor.Visit (this);
7701 // Array initializer expression, the expression is allowed in
7702 // variable or field initialization only which makes it tricky as
7703 // the type has to be infered based on the context either from field
7704 // type or variable type (think of multiple declarators)
7706 public class ArrayInitializer : Expression
7708 List<Expression> elements;
7709 BlockVariable variable;
7711 public ArrayInitializer (List<Expression> init, Location loc)
7717 public ArrayInitializer (int count, Location loc)
7718 : this (new List<Expression> (count), loc)
7722 public ArrayInitializer (Location loc)
7730 get { return elements.Count; }
7733 public List<Expression> Elements {
7739 public Expression this [int index] {
7741 return elements [index];
7745 public BlockVariable VariableDeclaration {
7756 public void Add (Expression expr)
7758 elements.Add (expr);
7761 public override bool ContainsEmitWithAwait ()
7763 throw new NotSupportedException ();
7766 public override Expression CreateExpressionTree (ResolveContext ec)
7768 throw new NotSupportedException ("ET");
7771 protected override void CloneTo (CloneContext clonectx, Expression t)
7773 var target = (ArrayInitializer) t;
7775 target.elements = new List<Expression> (elements.Count);
7776 foreach (var element in elements)
7777 target.elements.Add (element.Clone (clonectx));
7780 protected override Expression DoResolve (ResolveContext rc)
7782 var current_field = rc.CurrentMemberDefinition as FieldBase;
7783 TypeExpression type;
7784 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7785 type = new TypeExpression (current_field.MemberType, current_field.Location);
7786 } else if (variable != null) {
7787 if (variable.TypeExpression is VarExpr) {
7788 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7789 return EmptyExpression.Null;
7792 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7794 throw new NotImplementedException ("Unexpected array initializer context");
7797 return new ArrayCreation (type, this).Resolve (rc);
7800 public override void Emit (EmitContext ec)
7802 throw new InternalErrorException ("Missing Resolve call");
7805 public override void FlowAnalysis (FlowAnalysisContext fc)
7807 throw new InternalErrorException ("Missing Resolve call");
7810 public override object Accept (StructuralVisitor visitor)
7812 return visitor.Visit (this);
7817 /// 14.5.10.2: Represents an array creation expression.
7821 /// There are two possible scenarios here: one is an array creation
7822 /// expression that specifies the dimensions and optionally the
7823 /// initialization data and the other which does not need dimensions
7824 /// specified but where initialization data is mandatory.
7826 public class ArrayCreation : Expression
7828 FullNamedExpression requested_base_type;
7829 ArrayInitializer initializers;
7832 // The list of Argument types.
7833 // This is used to construct the `newarray' or constructor signature
7835 protected List<Expression> arguments;
7837 protected TypeSpec array_element_type;
7839 protected int dimensions;
7840 protected readonly ComposedTypeSpecifier rank;
7841 Expression first_emit;
7842 LocalTemporary first_emit_temp;
7844 protected List<Expression> array_data;
7846 Dictionary<int, int> bounds;
7849 // The number of constants in array initializers
7850 int const_initializers_count;
7851 bool only_constant_initializers;
7853 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7854 : this (requested_base_type, rank, initializers, l)
7856 arguments = new List<Expression> (exprs);
7857 num_arguments = arguments.Count;
7861 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7863 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7865 this.requested_base_type = requested_base_type;
7867 this.initializers = initializers;
7871 num_arguments = rank.Dimension;
7875 // For compiler generated single dimensional arrays only
7877 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7878 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7883 // For expressions like int[] foo = { 1, 2, 3 };
7885 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7886 : this (requested_base_type, null, initializers, initializers.Location)
7890 public bool NoEmptyInterpolation { get; set; }
7892 public ComposedTypeSpecifier Rank {
7898 public FullNamedExpression TypeExpression {
7900 return this.requested_base_type;
7904 public ArrayInitializer Initializers {
7906 return this.initializers;
7910 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7912 if (initializers != null && bounds == null) {
7914 // We use this to store all the data values in the order in which we
7915 // will need to store them in the byte blob later
7917 array_data = new List<Expression> (probe.Count);
7918 bounds = new Dictionary<int, int> ();
7921 if (specified_dims) {
7922 Expression a = arguments [idx];
7927 a = ConvertExpressionToArrayIndex (ec, a);
7933 if (initializers != null) {
7934 Constant c = a as Constant;
7935 if (c == null && a is ArrayIndexCast)
7936 c = ((ArrayIndexCast) a).Child as Constant;
7939 ec.Report.Error (150, a.Location, "A constant value is expected");
7945 value = System.Convert.ToInt32 (c.GetValue ());
7947 ec.Report.Error (150, a.Location, "A constant value is expected");
7951 // TODO: probe.Count does not fit ulong in
7952 if (value != probe.Count) {
7953 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7957 bounds[idx] = value;
7961 if (initializers == null)
7964 for (int i = 0; i < probe.Count; ++i) {
7966 if (o is ArrayInitializer) {
7967 var sub_probe = o as ArrayInitializer;
7968 if (idx + 1 >= dimensions){
7969 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7973 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7974 if (!bounds.ContainsKey(idx + 1))
7975 bounds[idx + 1] = sub_probe.Count;
7977 if (bounds[idx + 1] != sub_probe.Count) {
7978 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7982 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7985 } else if (child_bounds > 1) {
7986 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7988 Expression element = ResolveArrayElement (ec, o);
7989 if (element == null)
7992 // Initializers with the default values can be ignored
7993 Constant c = element as Constant;
7995 if (!c.IsDefaultInitializer (array_element_type)) {
7996 ++const_initializers_count;
7999 only_constant_initializers = false;
8002 array_data.Add (element);
8009 public override bool ContainsEmitWithAwait ()
8011 foreach (var arg in arguments) {
8012 if (arg.ContainsEmitWithAwait ())
8016 return InitializersContainAwait ();
8019 public override Expression CreateExpressionTree (ResolveContext ec)
8023 if (array_data == null) {
8024 args = new Arguments (arguments.Count + 1);
8025 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8026 foreach (Expression a in arguments)
8027 args.Add (new Argument (a.CreateExpressionTree (ec)));
8029 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8032 if (dimensions > 1) {
8033 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8037 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8038 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8039 if (array_data != null) {
8040 for (int i = 0; i < array_data.Count; ++i) {
8041 Expression e = array_data [i];
8042 args.Add (new Argument (e.CreateExpressionTree (ec)));
8046 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8049 void UpdateIndices (ResolveContext rc)
8052 for (var probe = initializers; probe != null;) {
8053 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8055 bounds[i++] = probe.Count;
8057 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8058 probe = (ArrayInitializer) probe[0];
8059 } else if (dimensions > i) {
8067 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8069 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8072 public override void FlowAnalysis (FlowAnalysisContext fc)
8074 foreach (var arg in arguments)
8075 arg.FlowAnalysis (fc);
8077 if (array_data != null) {
8078 foreach (var ad in array_data)
8079 ad.FlowAnalysis (fc);
8083 bool InitializersContainAwait ()
8085 if (array_data == null)
8088 foreach (var expr in array_data) {
8089 if (expr.ContainsEmitWithAwait ())
8096 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8098 element = element.Resolve (ec);
8099 if (element == null)
8102 var te = element as CompoundAssign.TargetExpression;
8104 for (int i = 1; i < initializers.Count; ++i) {
8105 if (initializers [i].ContainsEmitWithAwait ()) {
8106 te.RequiresEmitWithAwait = true;
8111 if (!te.RequiresEmitWithAwait) {
8112 if (first_emit != null)
8113 throw new InternalErrorException ("Can only handle one mutator at a time");
8114 first_emit = element;
8115 element = first_emit_temp = new LocalTemporary (element.Type);
8119 return Convert.ImplicitConversionRequired (
8120 ec, element, array_element_type, loc);
8123 protected bool ResolveInitializers (ResolveContext ec)
8126 only_constant_initializers = true;
8129 if (arguments != null) {
8131 for (int i = 0; i < arguments.Count; ++i) {
8132 res &= CheckIndices (ec, initializers, i, true, dimensions);
8133 if (initializers != null)
8140 arguments = new List<Expression> ();
8142 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8151 // Resolved the type of the array
8153 bool ResolveArrayType (ResolveContext ec)
8158 FullNamedExpression array_type_expr;
8159 if (num_arguments > 0) {
8160 array_type_expr = new ComposedCast (requested_base_type, rank);
8162 array_type_expr = requested_base_type;
8165 type = array_type_expr.ResolveAsType (ec);
8166 if (array_type_expr == null)
8169 var ac = type as ArrayContainer;
8171 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8175 array_element_type = ac.Element;
8176 dimensions = ac.Rank;
8181 protected override Expression DoResolve (ResolveContext ec)
8186 if (!ResolveArrayType (ec))
8190 // validate the initializers and fill in any missing bits
8192 if (!ResolveInitializers (ec))
8195 eclass = ExprClass.Value;
8199 byte [] MakeByteBlob ()
8204 int count = array_data.Count;
8206 TypeSpec element_type = array_element_type;
8207 if (element_type.IsEnum)
8208 element_type = EnumSpec.GetUnderlyingType (element_type);
8210 factor = BuiltinTypeSpec.GetSize (element_type);
8212 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8214 data = new byte [(count * factor + 3) & ~3];
8217 for (int i = 0; i < count; ++i) {
8218 var c = array_data[i] as Constant;
8224 object v = c.GetValue ();
8226 switch (element_type.BuiltinType) {
8227 case BuiltinTypeSpec.Type.Long:
8228 long lval = (long) v;
8230 for (int j = 0; j < factor; ++j) {
8231 data[idx + j] = (byte) (lval & 0xFF);
8235 case BuiltinTypeSpec.Type.ULong:
8236 ulong ulval = (ulong) v;
8238 for (int j = 0; j < factor; ++j) {
8239 data[idx + j] = (byte) (ulval & 0xFF);
8240 ulval = (ulval >> 8);
8243 case BuiltinTypeSpec.Type.Float:
8244 var fval = SingleConverter.SingleToInt32Bits((float) v);
8246 data[idx] = (byte) (fval & 0xff);
8247 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8248 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8249 data[idx + 3] = (byte) (fval >> 24);
8251 case BuiltinTypeSpec.Type.Double:
8252 element = BitConverter.GetBytes ((double) v);
8254 for (int j = 0; j < factor; ++j)
8255 data[idx + j] = element[j];
8257 // FIXME: Handle the ARM float format.
8258 if (!BitConverter.IsLittleEndian)
8259 System.Array.Reverse (data, idx, 8);
8261 case BuiltinTypeSpec.Type.Char:
8262 int chval = (int) ((char) v);
8264 data[idx] = (byte) (chval & 0xff);
8265 data[idx + 1] = (byte) (chval >> 8);
8267 case BuiltinTypeSpec.Type.Short:
8268 int sval = (int) ((short) v);
8270 data[idx] = (byte) (sval & 0xff);
8271 data[idx + 1] = (byte) (sval >> 8);
8273 case BuiltinTypeSpec.Type.UShort:
8274 int usval = (int) ((ushort) v);
8276 data[idx] = (byte) (usval & 0xff);
8277 data[idx + 1] = (byte) (usval >> 8);
8279 case BuiltinTypeSpec.Type.Int:
8282 data[idx] = (byte) (val & 0xff);
8283 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8284 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8285 data[idx + 3] = (byte) (val >> 24);
8287 case BuiltinTypeSpec.Type.UInt:
8288 uint uval = (uint) v;
8290 data[idx] = (byte) (uval & 0xff);
8291 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8292 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8293 data[idx + 3] = (byte) (uval >> 24);
8295 case BuiltinTypeSpec.Type.SByte:
8296 data[idx] = (byte) (sbyte) v;
8298 case BuiltinTypeSpec.Type.Byte:
8299 data[idx] = (byte) v;
8301 case BuiltinTypeSpec.Type.Bool:
8302 data[idx] = (byte) ((bool) v ? 1 : 0);
8304 case BuiltinTypeSpec.Type.Decimal:
8305 int[] bits = Decimal.GetBits ((decimal) v);
8308 // FIXME: For some reason, this doesn't work on the MS runtime.
8309 int[] nbits = new int[4];
8315 for (int j = 0; j < 4; j++) {
8316 data[p++] = (byte) (nbits[j] & 0xff);
8317 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8318 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8319 data[p++] = (byte) (nbits[j] >> 24);
8323 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8332 public override SLE.Expression MakeExpression (BuilderContext ctx)
8335 return base.MakeExpression (ctx);
8337 var initializers = new SLE.Expression [array_data.Count];
8338 for (var i = 0; i < initializers.Length; i++) {
8339 if (array_data [i] == null)
8340 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8342 initializers [i] = array_data [i].MakeExpression (ctx);
8345 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8350 // Emits the initializers for the array
8352 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8354 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8359 // First, the static data
8361 byte [] data = MakeByteBlob ();
8362 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8364 if (stackArray == null) {
8365 ec.Emit (OpCodes.Dup);
8367 stackArray.Emit (ec);
8370 ec.Emit (OpCodes.Ldtoken, fb);
8371 ec.Emit (OpCodes.Call, m);
8376 // Emits pieces of the array that can not be computed at compile
8377 // time (variables and string locations).
8379 // This always expect the top value on the stack to be the array
8381 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8383 int dims = bounds.Count;
8384 var current_pos = new int [dims];
8386 for (int i = 0; i < array_data.Count; i++){
8388 Expression e = array_data [i];
8389 var c = e as Constant;
8391 // Constant can be initialized via StaticInitializer
8392 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8396 if (stackArray != null) {
8397 if (e.ContainsEmitWithAwait ()) {
8398 e = e.EmitToField (ec);
8401 stackArray.EmitLoad (ec);
8403 ec.Emit (OpCodes.Dup);
8406 for (int idx = 0; idx < dims; idx++)
8407 ec.EmitInt (current_pos [idx]);
8410 // If we are dealing with a struct, get the
8411 // address of it, so we can store it.
8413 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8414 ec.Emit (OpCodes.Ldelema, etype);
8418 ec.EmitArrayStore ((ArrayContainer) type);
8424 for (int j = dims - 1; j >= 0; j--){
8426 if (current_pos [j] < bounds [j])
8428 current_pos [j] = 0;
8432 if (stackArray != null)
8433 stackArray.PrepareCleanup (ec);
8436 public override void Emit (EmitContext ec)
8438 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8441 var await_field = EmitToFieldSource (ec);
8442 if (await_field != null)
8443 await_field.Emit (ec);
8446 bool EmitOptimizedEmpty (EmitContext ec)
8448 if (arguments.Count != 1 || dimensions != 1)
8451 var c = arguments [0] as Constant;
8452 if (c == null || !c.IsZeroInteger)
8455 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8456 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8459 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8460 ec.Emit (OpCodes.Call, m);
8464 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8466 if (first_emit != null) {
8467 first_emit.Emit (ec);
8468 first_emit_temp.Store (ec);
8471 StackFieldExpr await_stack_field;
8472 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8473 await_stack_field = ec.GetTemporaryField (type);
8476 await_stack_field = null;
8479 EmitExpressionsList (ec, arguments);
8481 ec.EmitArrayNew ((ArrayContainer) type);
8483 if (initializers == null)
8484 return await_stack_field;
8486 if (await_stack_field != null)
8487 await_stack_field.EmitAssignFromStack (ec);
8491 // Emit static initializer for arrays which contain more than 2 items and
8492 // the static initializer will initialize at least 25% of array values or there
8493 // is more than 10 items to be initialized
8495 // NOTE: const_initializers_count does not contain default constant values.
8497 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8498 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8499 EmitStaticInitializers (ec, await_stack_field);
8501 if (!only_constant_initializers)
8502 EmitDynamicInitializers (ec, false, await_stack_field);
8506 EmitDynamicInitializers (ec, true, await_stack_field);
8509 if (first_emit_temp != null)
8510 first_emit_temp.Release (ec);
8512 return await_stack_field;
8515 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8517 // no multi dimensional or jagged arrays
8518 if (arguments.Count != 1 || array_element_type.IsArray) {
8519 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8523 // No array covariance, except for array -> object
8524 if (type != targetType) {
8525 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8526 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8530 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8531 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8536 // Single dimensional array of 0 size
8537 if (array_data == null) {
8538 IntConstant ic = arguments[0] as IntConstant;
8539 if (ic == null || !ic.IsDefaultValue) {
8540 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8548 enc.Encode (array_data.Count);
8549 foreach (var element in array_data) {
8550 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8554 protected override void CloneTo (CloneContext clonectx, Expression t)
8556 ArrayCreation target = (ArrayCreation) t;
8558 if (requested_base_type != null)
8559 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8561 if (arguments != null){
8562 target.arguments = new List<Expression> (arguments.Count);
8563 foreach (Expression e in arguments)
8564 target.arguments.Add (e.Clone (clonectx));
8567 if (initializers != null)
8568 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8571 public override object Accept (StructuralVisitor visitor)
8573 return visitor.Visit (this);
8578 // Represents an implicitly typed array epxression
8580 class ImplicitlyTypedArrayCreation : ArrayCreation
8582 TypeInferenceContext best_type_inference;
8584 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8585 : base (null, rank, initializers, loc)
8589 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8590 : base (null, initializers, loc)
8594 protected override Expression DoResolve (ResolveContext ec)
8599 dimensions = rank.Dimension;
8601 best_type_inference = new TypeInferenceContext ();
8603 if (!ResolveInitializers (ec))
8606 best_type_inference.FixAllTypes (ec);
8607 array_element_type = best_type_inference.InferredTypeArguments[0];
8608 best_type_inference = null;
8610 if (array_element_type == null ||
8611 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8612 arguments.Count != rank.Dimension) {
8613 ec.Report.Error (826, loc,
8614 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8619 // At this point we found common base type for all initializer elements
8620 // but we have to be sure that all static initializer elements are of
8623 UnifyInitializerElement (ec);
8625 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8626 eclass = ExprClass.Value;
8631 // Converts static initializer only
8633 void UnifyInitializerElement (ResolveContext ec)
8635 for (int i = 0; i < array_data.Count; ++i) {
8636 Expression e = array_data[i];
8638 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8642 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8644 element = element.Resolve (ec);
8645 if (element != null)
8646 best_type_inference.AddCommonTypeBound (element.Type);
8652 sealed class CompilerGeneratedThis : This
8654 public CompilerGeneratedThis (TypeSpec type, Location loc)
8660 protected override Expression DoResolve (ResolveContext rc)
8662 eclass = ExprClass.Variable;
8664 var block = rc.CurrentBlock;
8665 if (block != null) {
8666 var top = block.ParametersBlock.TopBlock;
8667 if (top.ThisVariable != null)
8668 variable_info = top.ThisVariable.VariableInfo;
8675 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8677 return DoResolve (rc);
8680 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8687 /// Represents the `this' construct
8690 public class This : VariableReference
8692 sealed class ThisVariable : ILocalVariable
8694 public static readonly ILocalVariable Instance = new ThisVariable ();
8696 public void Emit (EmitContext ec)
8701 public void EmitAssign (EmitContext ec)
8703 throw new InvalidOperationException ();
8706 public void EmitAddressOf (EmitContext ec)
8712 protected VariableInfo variable_info;
8714 public This (Location loc)
8721 public override string Name {
8722 get { return "this"; }
8725 public override bool IsLockedByStatement {
8733 public override bool IsRef {
8734 get { return type.IsStruct; }
8737 public override bool IsSideEffectFree {
8743 protected override ILocalVariable Variable {
8744 get { return ThisVariable.Instance; }
8747 public override VariableInfo VariableInfo {
8748 get { return variable_info; }
8751 public override bool IsFixed {
8752 get { return false; }
8757 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8760 // It's null for all cases when we don't need to check `this'
8761 // definitive assignment
8763 if (variable_info == null)
8766 if (fc.IsDefinitelyAssigned (variable_info))
8769 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8772 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8774 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8775 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8776 } else if (ec.CurrentAnonymousMethod != null) {
8777 ec.Report.Error (1673, loc,
8778 "Anonymous methods inside structs cannot access instance members of `this'. " +
8779 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8781 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8785 public override void FlowAnalysis (FlowAnalysisContext fc)
8787 CheckStructThisDefiniteAssignment (fc);
8790 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8795 AnonymousMethodStorey storey = ae.Storey;
8796 return storey != null ? storey.HoistedThis : null;
8799 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8801 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8804 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8807 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8813 public virtual void ResolveBase (ResolveContext ec)
8815 eclass = ExprClass.Variable;
8816 type = ec.CurrentType;
8818 if (!IsThisAvailable (ec, false)) {
8819 Error_ThisNotAvailable (ec);
8823 var block = ec.CurrentBlock;
8824 if (block != null) {
8825 var top = block.ParametersBlock.TopBlock;
8826 if (top.ThisVariable != null)
8827 variable_info = top.ThisVariable.VariableInfo;
8829 AnonymousExpression am = ec.CurrentAnonymousMethod;
8830 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8832 // Hoisted this is almost like hoisted variable but not exactly. When
8833 // there is no variable hoisted we can simply emit an instance method
8834 // without lifting this into a storey. Unfotunatelly this complicates
8835 // things in other cases because we don't know where this will be hoisted
8836 // until top-level block is fully resolved
8838 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8839 am.SetHasThisAccess ();
8844 protected override Expression DoResolve (ResolveContext ec)
8850 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8852 if (eclass == ExprClass.Unresolved)
8856 if (right_side == EmptyExpression.UnaryAddress)
8857 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8858 else if (right_side == EmptyExpression.OutAccess)
8859 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8861 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8867 public override int GetHashCode()
8869 throw new NotImplementedException ();
8872 public override bool Equals (object obj)
8874 This t = obj as This;
8881 protected override void CloneTo (CloneContext clonectx, Expression t)
8886 public override void SetHasAddressTaken ()
8891 public override object Accept (StructuralVisitor visitor)
8893 return visitor.Visit (this);
8898 /// Represents the `__arglist' construct
8900 public class ArglistAccess : Expression
8902 public ArglistAccess (Location loc)
8907 protected override void CloneTo (CloneContext clonectx, Expression target)
8912 public override bool ContainsEmitWithAwait ()
8917 public override Expression CreateExpressionTree (ResolveContext ec)
8919 throw new NotSupportedException ("ET");
8922 protected override Expression DoResolve (ResolveContext ec)
8924 eclass = ExprClass.Variable;
8925 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8927 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8928 ec.Report.Error (190, loc,
8929 "The __arglist construct is valid only within a variable argument method");
8935 public override void Emit (EmitContext ec)
8937 ec.Emit (OpCodes.Arglist);
8940 public override object Accept (StructuralVisitor visitor)
8942 return visitor.Visit (this);
8947 /// Represents the `__arglist (....)' construct
8949 public class Arglist : Expression
8951 Arguments arguments;
8953 public Arglist (Location loc)
8958 public Arglist (Arguments args, Location l)
8964 public Arguments Arguments {
8970 public MetaType[] ArgumentTypes {
8972 if (arguments == null)
8973 return MetaType.EmptyTypes;
8975 var retval = new MetaType[arguments.Count];
8976 for (int i = 0; i < retval.Length; i++)
8977 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8983 public override bool ContainsEmitWithAwait ()
8985 throw new NotImplementedException ();
8988 public override Expression CreateExpressionTree (ResolveContext ec)
8990 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8994 protected override Expression DoResolve (ResolveContext ec)
8996 eclass = ExprClass.Variable;
8997 type = InternalType.Arglist;
8998 if (arguments != null) {
8999 bool dynamic; // Can be ignored as there is always only 1 overload
9000 arguments.Resolve (ec, out dynamic);
9006 public override void Emit (EmitContext ec)
9008 if (arguments != null)
9009 arguments.Emit (ec);
9012 protected override void CloneTo (CloneContext clonectx, Expression t)
9014 Arglist target = (Arglist) t;
9016 if (arguments != null)
9017 target.arguments = arguments.Clone (clonectx);
9020 public override object Accept (StructuralVisitor visitor)
9022 return visitor.Visit (this);
9026 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9028 FullNamedExpression texpr;
9030 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9037 public FullNamedExpression TypeExpression {
9043 public override bool ContainsEmitWithAwait ()
9048 public void AddressOf (EmitContext ec, AddressOp mode)
9051 ec.Emit (OpCodes.Refanyval, type);
9054 protected override Expression DoResolve (ResolveContext rc)
9056 expr = expr.Resolve (rc);
9057 type = texpr.ResolveAsType (rc);
9058 if (expr == null || type == null)
9061 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9062 eclass = ExprClass.Variable;
9066 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9068 return DoResolve (rc);
9071 public override void Emit (EmitContext ec)
9074 ec.Emit (OpCodes.Refanyval, type);
9075 ec.EmitLoadFromPtr (type);
9078 public void Emit (EmitContext ec, bool leave_copy)
9080 throw new NotImplementedException ();
9083 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9086 ec.Emit (OpCodes.Refanyval, type);
9089 LocalTemporary temporary = null;
9091 ec.Emit (OpCodes.Dup);
9092 temporary = new LocalTemporary (source.Type);
9093 temporary.Store (ec);
9096 ec.EmitStoreFromPtr (type);
9098 if (temporary != null) {
9099 temporary.Emit (ec);
9100 temporary.Release (ec);
9104 public override object Accept (StructuralVisitor visitor)
9106 return visitor.Visit (this);
9110 public class RefTypeExpr : ShimExpression
9112 public RefTypeExpr (Expression expr, Location loc)
9118 protected override Expression DoResolve (ResolveContext rc)
9120 expr = expr.Resolve (rc);
9124 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9128 type = rc.BuiltinTypes.Type;
9129 eclass = ExprClass.Value;
9133 public override void Emit (EmitContext ec)
9136 ec.Emit (OpCodes.Refanytype);
9137 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9139 ec.Emit (OpCodes.Call, m);
9142 public override object Accept (StructuralVisitor visitor)
9144 return visitor.Visit (this);
9148 public class MakeRefExpr : ShimExpression
9150 public MakeRefExpr (Expression expr, Location loc)
9156 public override bool ContainsEmitWithAwait ()
9158 throw new NotImplementedException ();
9161 protected override Expression DoResolve (ResolveContext rc)
9163 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9164 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9165 eclass = ExprClass.Value;
9169 public override void Emit (EmitContext ec)
9171 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9172 ec.Emit (OpCodes.Mkrefany, expr.Type);
9175 public override object Accept (StructuralVisitor visitor)
9177 return visitor.Visit (this);
9182 /// Implements the typeof operator
9184 public class TypeOf : Expression {
9185 FullNamedExpression QueriedType;
9188 public TypeOf (FullNamedExpression queried_type, Location l)
9190 QueriedType = queried_type;
9195 // Use this constructor for any compiler generated typeof expression
9197 public TypeOf (TypeSpec type, Location loc)
9199 this.typearg = type;
9205 public override bool IsSideEffectFree {
9211 public TypeSpec TypeArgument {
9217 public FullNamedExpression TypeExpression {
9226 protected override void CloneTo (CloneContext clonectx, Expression t)
9228 TypeOf target = (TypeOf) t;
9229 if (QueriedType != null)
9230 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9233 public override bool ContainsEmitWithAwait ()
9238 public override Expression CreateExpressionTree (ResolveContext ec)
9240 Arguments args = new Arguments (2);
9241 args.Add (new Argument (this));
9242 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9243 return CreateExpressionFactoryCall (ec, "Constant", args);
9246 protected override Expression DoResolve (ResolveContext ec)
9248 if (eclass != ExprClass.Unresolved)
9251 if (typearg == null) {
9253 // Pointer types are allowed without explicit unsafe, they are just tokens
9255 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9256 typearg = QueriedType.ResolveAsType (ec, true);
9259 if (typearg == null)
9262 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9263 ec.Report.Error (1962, QueriedType.Location,
9264 "The typeof operator cannot be used on the dynamic type");
9268 type = ec.BuiltinTypes.Type;
9270 // Even though what is returned is a type object, it's treated as a value by the compiler.
9271 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9272 eclass = ExprClass.Value;
9276 static bool ContainsDynamicType (TypeSpec type)
9278 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9281 var element_container = type as ElementTypeSpec;
9282 if (element_container != null)
9283 return ContainsDynamicType (element_container.Element);
9285 foreach (var t in type.TypeArguments) {
9286 if (ContainsDynamicType (t)) {
9294 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9296 // Target type is not System.Type therefore must be object
9297 // and we need to use different encoding sequence
9298 if (targetType != type)
9301 if (typearg is InflatedTypeSpec) {
9304 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9305 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9306 typearg.GetSignatureForError ());
9310 gt = gt.DeclaringType;
9311 } while (gt != null);
9314 if (ContainsDynamicType (typearg)) {
9315 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9319 enc.EncodeTypeName (typearg);
9322 public override void Emit (EmitContext ec)
9324 ec.Emit (OpCodes.Ldtoken, typearg);
9325 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9327 ec.Emit (OpCodes.Call, m);
9330 public override object Accept (StructuralVisitor visitor)
9332 return visitor.Visit (this);
9336 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9338 public TypeOfMethod (MethodSpec method, Location loc)
9339 : base (method, loc)
9343 protected override Expression DoResolve (ResolveContext ec)
9345 if (member.IsConstructor) {
9346 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9348 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9354 return base.DoResolve (ec);
9357 public override void Emit (EmitContext ec)
9359 ec.Emit (OpCodes.Ldtoken, member);
9362 ec.Emit (OpCodes.Castclass, type);
9365 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9367 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9370 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9372 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9376 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9378 protected readonly T member;
9380 protected TypeOfMember (T member, Location loc)
9382 this.member = member;
9386 public override bool IsSideEffectFree {
9392 public override bool ContainsEmitWithAwait ()
9397 public override Expression CreateExpressionTree (ResolveContext ec)
9399 Arguments args = new Arguments (2);
9400 args.Add (new Argument (this));
9401 args.Add (new Argument (new TypeOf (type, loc)));
9402 return CreateExpressionFactoryCall (ec, "Constant", args);
9405 protected override Expression DoResolve (ResolveContext ec)
9407 eclass = ExprClass.Value;
9411 public override void Emit (EmitContext ec)
9413 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9414 PredefinedMember<MethodSpec> p;
9416 p = GetTypeFromHandleGeneric (ec);
9417 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9419 p = GetTypeFromHandle (ec);
9422 var mi = p.Resolve (loc);
9424 ec.Emit (OpCodes.Call, mi);
9427 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9428 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9431 sealed class TypeOfField : TypeOfMember<FieldSpec>
9433 public TypeOfField (FieldSpec field, Location loc)
9438 protected override Expression DoResolve (ResolveContext ec)
9440 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9444 return base.DoResolve (ec);
9447 public override void Emit (EmitContext ec)
9449 ec.Emit (OpCodes.Ldtoken, member);
9453 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9455 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9458 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9460 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9465 /// Implements the sizeof expression
9467 public class SizeOf : Expression {
9468 readonly Expression texpr;
9469 TypeSpec type_queried;
9471 public SizeOf (Expression queried_type, Location l)
9473 this.texpr = queried_type;
9477 public override bool IsSideEffectFree {
9483 public Expression TypeExpression {
9489 public override bool ContainsEmitWithAwait ()
9494 public override Expression CreateExpressionTree (ResolveContext ec)
9496 Error_PointerInsideExpressionTree (ec);
9500 protected override Expression DoResolve (ResolveContext ec)
9502 type_queried = texpr.ResolveAsType (ec);
9503 if (type_queried == null)
9506 if (type_queried.IsEnum)
9507 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9509 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9511 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9514 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9519 ec.Report.Error (233, loc,
9520 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9521 type_queried.GetSignatureForError ());
9524 type = ec.BuiltinTypes.Int;
9525 eclass = ExprClass.Value;
9529 public override void Emit (EmitContext ec)
9531 ec.Emit (OpCodes.Sizeof, type_queried);
9534 protected override void CloneTo (CloneContext clonectx, Expression t)
9538 public override object Accept (StructuralVisitor visitor)
9540 return visitor.Visit (this);
9545 /// Implements the qualified-alias-member (::) expression.
9547 public class QualifiedAliasMember : MemberAccess
9549 readonly string alias;
9550 public static readonly string GlobalAlias = "global";
9552 public QualifiedAliasMember (string alias, string identifier, Location l)
9553 : base (null, identifier, l)
9558 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9559 : base (null, identifier, targs, l)
9564 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9565 : base (null, identifier, arity, l)
9570 public string Alias {
9576 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9578 if (alias == GlobalAlias)
9579 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9581 int errors = mc.Module.Compiler.Report.Errors;
9582 var expr = mc.LookupNamespaceAlias (alias);
9584 if (errors == mc.Module.Compiler.Report.Errors)
9585 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9593 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9595 expr = CreateExpressionFromAlias (mc);
9599 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9602 protected override Expression DoResolve (ResolveContext rc)
9604 return ResolveAsTypeOrNamespace (rc, false);
9607 public override string GetSignatureForError ()
9610 if (targs != null) {
9611 name = Name + "<" + targs.GetSignatureForError () + ">";
9614 return alias + "::" + name;
9617 public override bool HasConditionalAccess ()
9622 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9624 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9625 rc.Module.Compiler.Report.Error (687, loc,
9626 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9627 GetSignatureForError ());
9632 return DoResolve (rc);
9635 protected override void CloneTo (CloneContext clonectx, Expression t)
9640 public override object Accept (StructuralVisitor visitor)
9642 return visitor.Visit (this);
9647 /// Implements the member access expression
9649 public class MemberAccess : ATypeNameExpression
9651 protected Expression expr;
9653 public MemberAccess (Expression expr, string id)
9654 : base (id, expr.Location)
9659 public MemberAccess (Expression expr, string identifier, Location loc)
9660 : base (identifier, loc)
9665 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9666 : base (identifier, args, loc)
9671 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9672 : base (identifier, arity, loc)
9677 public Expression LeftExpression {
9683 public override Location StartLocation {
9685 return expr == null ? loc : expr.StartLocation;
9689 protected override Expression DoResolve (ResolveContext rc)
9691 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9693 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9698 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9700 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9702 if (e is TypeExpr) {
9703 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9708 e = e.ResolveLValue (rc, rhs);
9713 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9715 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9716 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9718 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9721 public override bool HasConditionalAccess ()
9723 return LeftExpression.HasConditionalAccess ();
9726 public static bool IsValidDotExpression (TypeSpec type)
9728 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9729 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9731 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9734 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9736 var sn = expr as SimpleName;
9737 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9740 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9743 // Resolve expression which does have type set as we need expression type
9744 // with disable flow analysis as we don't know whether left side expression
9745 // is used as variable or type
9747 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9748 expr = expr.Resolve (rc);
9749 } else if (expr is TypeParameterExpr) {
9750 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9754 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9755 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9756 expr = expr.Resolve (rc, flags);
9759 expr = expr.Resolve (rc, flags);
9766 var ns = expr as NamespaceExpression;
9768 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9770 if (retval == null) {
9771 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9776 if (HasTypeArguments)
9777 return new GenericTypeExpr (retval.Type, targs, loc);
9779 targs.Resolve (rc, false);
9785 var cma = this as ConditionalMemberAccess;
9788 TypeSpec expr_type = expr.Type;
9789 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9790 me = expr as MemberExpr;
9792 me.ResolveInstanceExpression (rc, null);
9794 Arguments args = new Arguments (1);
9795 args.Add (new Argument (expr));
9798 return new DynamicConditionalMemberBinder (Name, args, loc);
9800 return new DynamicMemberBinder (Name, args, loc);
9804 if (!IsNullPropagatingValid (expr.Type)) {
9805 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9809 if (expr_type.IsNullableType) {
9810 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9811 expr_type = expr.Type;
9815 if (!IsValidDotExpression (expr_type)) {
9816 Error_OperatorCannotBeApplied (rc, expr_type);
9820 var lookup_arity = Arity;
9821 bool errorMode = false;
9822 Expression member_lookup;
9824 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9825 if (member_lookup == null) {
9827 // Try to look for extension method when member lookup failed
9829 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9830 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9831 if (methods != null) {
9832 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9833 if (HasTypeArguments) {
9834 if (!targs.Resolve (rc, false))
9837 emg.SetTypeArguments (rc, targs);
9841 emg.ConditionalAccess = true;
9843 // TODO: it should really skip the checks bellow
9844 return emg.Resolve (rc);
9850 if (member_lookup == null) {
9851 var dep = expr_type.GetMissingDependencies ();
9853 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9854 } else if (expr is TypeExpr) {
9855 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9857 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9863 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9864 // Leave it to overload resolution to report correct error
9865 } else if (!(member_lookup is TypeExpr)) {
9866 // TODO: rc.SymbolRelatedToPreviousError
9867 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9872 if (member_lookup != null)
9876 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9880 TypeExpr texpr = member_lookup as TypeExpr;
9881 if (texpr != null) {
9882 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9883 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9884 Name, texpr.GetSignatureForError ());
9887 if (!texpr.Type.IsAccessible (rc)) {
9888 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9889 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9893 if (HasTypeArguments) {
9894 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9897 return member_lookup;
9900 me = member_lookup as MemberExpr;
9902 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9907 me.ConditionalAccess = true;
9910 me = me.ResolveMemberAccess (rc, expr, sn);
9913 if (!targs.Resolve (rc, false))
9916 me.SetTypeArguments (rc, targs);
9922 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9924 FullNamedExpression fexpr = expr as FullNamedExpression;
9925 if (fexpr == null) {
9926 expr.ResolveAsType (rc);
9930 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9932 if (expr_resolved == null)
9935 var ns = expr_resolved as NamespaceExpression;
9937 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9939 if (retval == null) {
9940 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9941 } else if (Arity > 0) {
9942 if (HasTypeArguments) {
9943 retval = new GenericTypeExpr (retval.Type, targs, loc);
9944 if (retval.ResolveAsType (rc) == null)
9947 targs.Resolve (rc, allowUnboundTypeArguments);
9949 retval = new GenericOpenTypeExpr (retval.Type, loc);
9956 var tnew_expr = expr_resolved.ResolveAsType (rc);
9957 if (tnew_expr == null)
9960 TypeSpec expr_type = tnew_expr;
9961 if (TypeManager.IsGenericParameter (expr_type)) {
9962 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9963 tnew_expr.GetSignatureForError ());
9967 var qam = this as QualifiedAliasMember;
9969 rc.Module.Compiler.Report.Error (431, loc,
9970 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9975 TypeSpec nested = null;
9976 while (expr_type != null) {
9977 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9978 if (nested == null) {
9979 if (expr_type == tnew_expr) {
9980 Error_IdentifierNotFound (rc, expr_type);
9984 expr_type = tnew_expr;
9985 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9986 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9990 if (nested.IsAccessible (rc))
9994 // Keep looking after inaccessible candidate but only if
9995 // we are not in same context as the definition itself
9997 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10000 expr_type = expr_type.BaseType;
10005 if (HasTypeArguments) {
10006 texpr = new GenericTypeExpr (nested, targs, loc);
10008 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10010 texpr = new GenericOpenTypeExpr (nested, loc);
10012 } else if (expr_resolved is GenericOpenTypeExpr) {
10013 texpr = new GenericOpenTypeExpr (nested, loc);
10015 texpr = new TypeExpression (nested, loc);
10018 if (texpr.ResolveAsType (rc) == null)
10024 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10026 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10028 if (nested != null) {
10029 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10033 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10034 if (any_other_member != null) {
10035 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10039 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10040 Name, expr_type.GetSignatureForError ());
10043 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10045 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10048 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10050 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10051 ec.Report.SymbolRelatedToPreviousError (type);
10053 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10055 // a using directive or an assembly reference
10056 if (cand != null) {
10057 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10059 missing = "an assembly reference";
10062 ec.Report.Error (1061, loc,
10063 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10064 type.GetSignatureForError (), name, missing);
10068 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10071 public override string GetSignatureForError ()
10073 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10076 protected override void CloneTo (CloneContext clonectx, Expression t)
10078 MemberAccess target = (MemberAccess) t;
10080 target.expr = expr.Clone (clonectx);
10083 public override object Accept (StructuralVisitor visitor)
10085 return visitor.Visit (this);
10089 public class ConditionalMemberAccess : MemberAccess
10091 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10092 : base (expr, identifier, args, loc)
10096 public override bool HasConditionalAccess ()
10103 /// Implements checked expressions
10105 public class CheckedExpr : Expression {
10107 public Expression Expr;
10109 public CheckedExpr (Expression e, Location l)
10115 public override bool ContainsEmitWithAwait ()
10117 return Expr.ContainsEmitWithAwait ();
10120 public override Expression CreateExpressionTree (ResolveContext ec)
10122 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10123 return Expr.CreateExpressionTree (ec);
10126 protected override Expression DoResolve (ResolveContext ec)
10128 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10129 Expr = Expr.Resolve (ec);
10134 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10137 eclass = Expr.eclass;
10142 public override void Emit (EmitContext ec)
10144 using (ec.With (EmitContext.Options.CheckedScope, true))
10148 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10150 using (ec.With (EmitContext.Options.CheckedScope, true))
10151 Expr.EmitBranchable (ec, target, on_true);
10154 public override void FlowAnalysis (FlowAnalysisContext fc)
10156 Expr.FlowAnalysis (fc);
10159 public override SLE.Expression MakeExpression (BuilderContext ctx)
10161 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10162 return Expr.MakeExpression (ctx);
10166 protected override void CloneTo (CloneContext clonectx, Expression t)
10168 CheckedExpr target = (CheckedExpr) t;
10170 target.Expr = Expr.Clone (clonectx);
10173 public override object Accept (StructuralVisitor visitor)
10175 return visitor.Visit (this);
10180 /// Implements the unchecked expression
10182 public class UnCheckedExpr : Expression {
10184 public Expression Expr;
10186 public UnCheckedExpr (Expression e, Location l)
10192 public override bool ContainsEmitWithAwait ()
10194 return Expr.ContainsEmitWithAwait ();
10197 public override Expression CreateExpressionTree (ResolveContext ec)
10199 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10200 return Expr.CreateExpressionTree (ec);
10203 protected override Expression DoResolve (ResolveContext ec)
10205 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10206 Expr = Expr.Resolve (ec);
10211 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10214 eclass = Expr.eclass;
10219 public override void Emit (EmitContext ec)
10221 using (ec.With (EmitContext.Options.CheckedScope, false))
10225 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10227 using (ec.With (EmitContext.Options.CheckedScope, false))
10228 Expr.EmitBranchable (ec, target, on_true);
10231 public override void FlowAnalysis (FlowAnalysisContext fc)
10233 Expr.FlowAnalysis (fc);
10236 protected override void CloneTo (CloneContext clonectx, Expression t)
10238 UnCheckedExpr target = (UnCheckedExpr) t;
10240 target.Expr = Expr.Clone (clonectx);
10243 public override object Accept (StructuralVisitor visitor)
10245 return visitor.Visit (this);
10250 /// An Element Access expression.
10252 /// During semantic analysis these are transformed into
10253 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10255 public class ElementAccess : Expression
10257 public Arguments Arguments;
10258 public Expression Expr;
10259 bool conditional_access_receiver;
10261 public ElementAccess (Expression e, Arguments args, Location loc)
10265 this.Arguments = args;
10268 public bool ConditionalAccess { get; set; }
10270 public override Location StartLocation {
10272 return Expr.StartLocation;
10276 public override bool ContainsEmitWithAwait ()
10278 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10282 // We perform some simple tests, and then to "split" the emit and store
10283 // code we create an instance of a different class, and return that.
10285 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10287 if (conditionalAccessReceiver)
10288 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10290 Expr = Expr.Resolve (ec);
10292 if (conditionalAccessReceiver)
10293 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10300 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10301 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10305 if (type.IsArray) {
10306 var aa = new ArrayAccess (this, loc) {
10307 ConditionalAccess = ConditionalAccess,
10310 if (conditionalAccessReceiver)
10311 aa.SetConditionalAccessReceiver ();
10316 if (type.IsPointer)
10317 return Expr.MakePointerAccess (ec, type, Arguments);
10319 FieldExpr fe = Expr as FieldExpr;
10321 var ff = fe.Spec as FixedFieldSpec;
10323 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10327 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10328 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10329 var indexer = new IndexerExpr (indexers, type, this) {
10330 ConditionalAccess = ConditionalAccess
10333 if (conditionalAccessReceiver)
10334 indexer.SetConditionalAccessReceiver ();
10339 Error_CannotApplyIndexing (ec, type, loc);
10344 public override Expression CreateExpressionTree (ResolveContext ec)
10346 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10347 Expr.CreateExpressionTree (ec));
10349 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10352 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10354 if (type != InternalType.ErrorType) {
10355 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10356 type.GetSignatureForError ());
10360 public override bool HasConditionalAccess ()
10362 return ConditionalAccess || Expr.HasConditionalAccess ();
10365 void ResolveConditionalAccessReceiver (ResolveContext rc)
10367 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10368 conditional_access_receiver = true;
10372 protected override Expression DoResolve (ResolveContext rc)
10374 ResolveConditionalAccessReceiver (rc);
10376 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10380 return expr.Resolve (rc);
10383 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10385 var res = CreateAccessExpression (ec, false);
10389 return res.ResolveLValue (ec, rhs);
10392 public override void Emit (EmitContext ec)
10394 throw new Exception ("Should never be reached");
10397 public override void FlowAnalysis (FlowAnalysisContext fc)
10399 Expr.FlowAnalysis (fc);
10401 Arguments.FlowAnalysis (fc);
10404 public override string GetSignatureForError ()
10406 return Expr.GetSignatureForError ();
10409 protected override void CloneTo (CloneContext clonectx, Expression t)
10411 ElementAccess target = (ElementAccess) t;
10413 target.Expr = Expr.Clone (clonectx);
10414 if (Arguments != null)
10415 target.Arguments = Arguments.Clone (clonectx);
10418 public override object Accept (StructuralVisitor visitor)
10420 return visitor.Visit (this);
10425 /// Implements array access
10427 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10429 // Points to our "data" repository
10433 LocalTemporary temp;
10435 bool? has_await_args;
10436 bool conditional_access_receiver;
10438 public ArrayAccess (ElementAccess ea_data, Location l)
10444 public bool ConditionalAccess { get; set; }
10446 public void AddressOf (EmitContext ec, AddressOp mode)
10448 var ac = (ArrayContainer) ea.Expr.Type;
10450 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10451 LoadInstanceAndArguments (ec, false, true);
10454 LoadInstanceAndArguments (ec, false, false);
10456 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10457 ec.Emit (OpCodes.Readonly);
10459 ec.EmitArrayAddress (ac);
10462 public override Expression CreateExpressionTree (ResolveContext ec)
10464 if (ConditionalAccess)
10465 Error_NullShortCircuitInsideExpressionTree (ec);
10467 return ea.CreateExpressionTree (ec);
10470 public override bool ContainsEmitWithAwait ()
10472 return ea.ContainsEmitWithAwait ();
10475 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10477 if (HasConditionalAccess ())
10478 Error_NullPropagatingLValue (ec);
10480 return DoResolve (ec);
10483 protected override Expression DoResolve (ResolveContext ec)
10485 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10487 ea.Arguments.Resolve (ec, out dynamic);
10489 var ac = ea.Expr.Type as ArrayContainer;
10490 int rank = ea.Arguments.Count;
10491 if (ac.Rank != rank) {
10492 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10493 rank.ToString (), ac.Rank.ToString ());
10498 if (type.IsPointer) {
10499 if (ec.CurrentIterator != null) {
10500 UnsafeInsideIteratorError (ec, ea.Location);
10501 } else if (!ec.IsUnsafe) {
10502 UnsafeError (ec, ea.Location);
10506 if (conditional_access_receiver)
10507 type = LiftMemberType (ec, type);
10509 foreach (Argument a in ea.Arguments) {
10510 var na = a as NamedArgument;
10512 ElementAccess.Error_NamedArgument (na, ec.Report);
10514 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10517 eclass = ExprClass.Variable;
10522 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10524 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10527 public override void FlowAnalysis (FlowAnalysisContext fc)
10529 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10531 ea.FlowAnalysis (fc);
10533 if (conditional_access_receiver)
10534 fc.DefiniteAssignment = da;
10537 public override bool HasConditionalAccess ()
10539 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10543 // Load the array arguments into the stack.
10545 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10547 if (prepareAwait) {
10548 ea.Expr = ea.Expr.EmitToField (ec);
10550 var ie = new InstanceEmitter (ea.Expr, false);
10551 ie.Emit (ec, ConditionalAccess);
10553 if (duplicateArguments) {
10554 ec.Emit (OpCodes.Dup);
10556 var copy = new LocalTemporary (ea.Expr.Type);
10562 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10563 if (dup_args != null)
10564 ea.Arguments = dup_args;
10567 public void Emit (EmitContext ec, bool leave_copy)
10570 ec.EmitLoadFromPtr (type);
10572 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10573 LoadInstanceAndArguments (ec, false, true);
10576 if (conditional_access_receiver)
10577 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10579 var ac = (ArrayContainer) ea.Expr.Type;
10580 LoadInstanceAndArguments (ec, false, false);
10581 ec.EmitArrayLoad (ac);
10583 if (conditional_access_receiver)
10584 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10588 ec.Emit (OpCodes.Dup);
10589 temp = new LocalTemporary (this.type);
10594 public override void Emit (EmitContext ec)
10599 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10601 var ac = (ArrayContainer) ea.Expr.Type;
10602 TypeSpec t = source.Type;
10604 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10607 // When we are dealing with a struct, get the address of it to avoid value copy
10608 // Same cannot be done for reference type because array covariance and the
10609 // check in ldelema requires to specify the type of array element stored at the index
10611 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10612 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10614 if (has_await_args.Value) {
10615 if (source.ContainsEmitWithAwait ()) {
10616 source = source.EmitToField (ec);
10617 isCompound = false;
10621 LoadInstanceAndArguments (ec, isCompound, false);
10626 ec.EmitArrayAddress (ac);
10629 ec.Emit (OpCodes.Dup);
10633 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10635 if (has_await_args.Value) {
10636 if (source.ContainsEmitWithAwait ())
10637 source = source.EmitToField (ec);
10639 LoadInstanceAndArguments (ec, false, false);
10646 var lt = ea.Expr as LocalTemporary;
10652 ec.Emit (OpCodes.Dup);
10653 temp = new LocalTemporary (this.type);
10658 ec.EmitStoreFromPtr (t);
10660 ec.EmitArrayStore (ac);
10663 if (temp != null) {
10669 public override Expression EmitToField (EmitContext ec)
10672 // Have to be specialized for arrays to get access to
10673 // underlying element. Instead of another result copy we
10674 // need direct access to element
10678 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10680 ea.Expr = ea.Expr.EmitToField (ec);
10681 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10685 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10687 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10690 public override SLE.Expression MakeExpression (BuilderContext ctx)
10692 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10695 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10697 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10698 return Arguments.MakeExpression (ea.Arguments, ctx);
10702 public void SetConditionalAccessReceiver ()
10704 conditional_access_receiver = true;
10709 // Indexer access expression
10711 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10713 IList<MemberSpec> indexers;
10714 Arguments arguments;
10715 TypeSpec queried_type;
10717 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10718 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10722 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10725 this.indexers = indexers;
10726 this.queried_type = queriedType;
10727 this.InstanceExpression = instance;
10728 this.arguments = args;
10733 protected override Arguments Arguments {
10742 protected override TypeSpec DeclaringType {
10744 return best_candidate.DeclaringType;
10748 public override bool IsInstance {
10754 public override bool IsStatic {
10760 public override string KindName {
10761 get { return "indexer"; }
10764 public override string Name {
10772 public override bool ContainsEmitWithAwait ()
10774 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10777 public override Expression CreateExpressionTree (ResolveContext ec)
10779 if (ConditionalAccess) {
10780 Error_NullShortCircuitInsideExpressionTree (ec);
10783 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10784 InstanceExpression.CreateExpressionTree (ec),
10785 new TypeOfMethod (Getter, loc));
10787 return CreateExpressionFactoryCall (ec, "Call", args);
10790 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10792 LocalTemporary await_source_arg = null;
10795 emitting_compound_assignment = true;
10796 if (source is DynamicExpressionStatement) {
10801 emitting_compound_assignment = false;
10803 if (has_await_arguments) {
10804 await_source_arg = new LocalTemporary (Type);
10805 await_source_arg.Store (ec);
10807 arguments.Add (new Argument (await_source_arg));
10810 temp = await_source_arg;
10813 has_await_arguments = false;
10818 ec.Emit (OpCodes.Dup);
10819 temp = new LocalTemporary (Type);
10825 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10826 source = source.EmitToField (ec);
10828 temp = new LocalTemporary (Type);
10835 arguments.Add (new Argument (source));
10838 var call = new CallEmitter ();
10839 call.InstanceExpression = InstanceExpression;
10840 if (arguments == null)
10841 call.InstanceExpressionOnStack = true;
10843 call.Emit (ec, Setter, arguments, loc);
10845 if (temp != null) {
10848 } else if (leave_copy) {
10852 if (await_source_arg != null) {
10853 await_source_arg.Release (ec);
10857 public override void FlowAnalysis (FlowAnalysisContext fc)
10859 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10861 base.FlowAnalysis (fc);
10862 arguments.FlowAnalysis (fc);
10864 if (conditional_access_receiver)
10865 fc.DefiniteAssignment = da;
10868 public override string GetSignatureForError ()
10870 return best_candidate.GetSignatureForError ();
10873 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10876 throw new NotSupportedException ();
10878 var value = new[] { source.MakeExpression (ctx) };
10879 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10880 return SLE.Expression.Block (
10881 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10886 public override SLE.Expression MakeExpression (BuilderContext ctx)
10889 return base.MakeExpression (ctx);
10891 var args = Arguments.MakeExpression (arguments, ctx);
10892 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10896 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10898 if (best_candidate != null)
10901 eclass = ExprClass.IndexerAccess;
10904 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10905 arguments.Resolve (rc, out dynamic);
10908 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10911 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10912 res.BaseMembersProvider = this;
10913 res.InstanceQualifier = this;
10915 // TODO: Do I need 2 argument sets?
10916 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10917 if (best_candidate != null)
10918 type = res.BestCandidateReturnType;
10919 else if (!res.BestCandidateIsDynamic)
10924 // It has dynamic arguments
10927 Arguments args = new Arguments (arguments.Count + 1);
10929 rc.Report.Error (1972, loc,
10930 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10932 args.Add (new Argument (InstanceExpression));
10934 args.AddRange (arguments);
10936 best_candidate = null;
10937 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10941 // Try to avoid resolving left expression again
10943 if (right_side != null)
10944 ResolveInstanceExpression (rc, right_side);
10949 protected override void CloneTo (CloneContext clonectx, Expression t)
10951 IndexerExpr target = (IndexerExpr) t;
10953 if (arguments != null)
10954 target.arguments = arguments.Clone (clonectx);
10957 public void SetConditionalAccessReceiver ()
10959 conditional_access_receiver = true;
10962 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10964 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10967 #region IBaseMembersProvider Members
10969 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
10971 var baseType = type.BaseType;
10972 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10974 if (members == null && !type.IsInterface) {
10975 var tps = queried_type as TypeParameterSpec;
10977 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
10983 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10985 if (queried_type == member.DeclaringType)
10988 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10989 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10992 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11001 // A base access expression
11003 public class BaseThis : This
11005 public BaseThis (Location loc)
11010 public BaseThis (TypeSpec type, Location loc)
11014 eclass = ExprClass.Variable;
11019 public override string Name {
11027 public override Expression CreateExpressionTree (ResolveContext ec)
11029 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11030 return base.CreateExpressionTree (ec);
11033 public override void Emit (EmitContext ec)
11037 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11038 var context_type = ec.CurrentType;
11039 ec.Emit (OpCodes.Ldobj, context_type);
11040 ec.Emit (OpCodes.Box, context_type);
11044 protected override void Error_ThisNotAvailable (ResolveContext ec)
11047 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11049 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11053 public override void ResolveBase (ResolveContext ec)
11055 base.ResolveBase (ec);
11056 type = ec.CurrentType.BaseType;
11059 public override object Accept (StructuralVisitor visitor)
11061 return visitor.Visit (this);
11066 /// This class exists solely to pass the Type around and to be a dummy
11067 /// that can be passed to the conversion functions (this is used by
11068 /// foreach implementation to typecast the object return value from
11069 /// get_Current into the proper type. All code has been generated and
11070 /// we only care about the side effect conversions to be performed
11072 /// This is also now used as a placeholder where a no-action expression
11073 /// is needed (the `New' class).
11075 public class EmptyExpression : Expression
11077 sealed class OutAccessExpression : EmptyExpression
11079 public OutAccessExpression (TypeSpec t)
11084 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11086 rc.Report.Error (206, right_side.Location,
11087 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11093 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11094 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11095 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11096 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11097 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11098 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11099 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11100 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11102 public EmptyExpression (TypeSpec t)
11105 eclass = ExprClass.Value;
11106 loc = Location.Null;
11109 protected override void CloneTo (CloneContext clonectx, Expression target)
11113 public override bool ContainsEmitWithAwait ()
11118 public override Expression CreateExpressionTree (ResolveContext ec)
11120 throw new NotSupportedException ("ET");
11123 protected override Expression DoResolve (ResolveContext ec)
11128 public override void Emit (EmitContext ec)
11130 // nothing, as we only exist to not do anything.
11133 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11137 public override void EmitSideEffect (EmitContext ec)
11141 public override object Accept (StructuralVisitor visitor)
11143 return visitor.Visit (this);
11147 sealed class EmptyAwaitExpression : EmptyExpression
11149 public EmptyAwaitExpression (TypeSpec type)
11154 public override bool ContainsEmitWithAwait ()
11161 // Empty statement expression
11163 public sealed class EmptyExpressionStatement : ExpressionStatement
11165 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11167 private EmptyExpressionStatement ()
11169 loc = Location.Null;
11172 public override bool ContainsEmitWithAwait ()
11177 public override Expression CreateExpressionTree (ResolveContext ec)
11182 public override void EmitStatement (EmitContext ec)
11187 protected override Expression DoResolve (ResolveContext ec)
11189 eclass = ExprClass.Value;
11190 type = ec.BuiltinTypes.Object;
11194 public override void Emit (EmitContext ec)
11199 public override object Accept (StructuralVisitor visitor)
11201 return visitor.Visit (this);
11205 public class ErrorExpression : EmptyExpression
11207 public static readonly ErrorExpression Instance = new ErrorExpression ();
11209 private ErrorExpression ()
11210 : base (InternalType.ErrorType)
11214 public override Expression CreateExpressionTree (ResolveContext ec)
11219 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11224 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11228 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11232 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11236 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11240 public override object Accept (StructuralVisitor visitor)
11242 return visitor.Visit (this);
11246 public class UserCast : Expression {
11250 public UserCast (MethodSpec method, Expression source, Location l)
11252 if (source == null)
11253 throw new ArgumentNullException ("source");
11255 this.method = method;
11256 this.source = source;
11257 type = method.ReturnType;
11261 public Expression Source {
11270 public override bool ContainsEmitWithAwait ()
11272 return source.ContainsEmitWithAwait ();
11275 public override Expression CreateExpressionTree (ResolveContext ec)
11277 Arguments args = new Arguments (3);
11278 args.Add (new Argument (source.CreateExpressionTree (ec)));
11279 args.Add (new Argument (new TypeOf (type, loc)));
11280 args.Add (new Argument (new TypeOfMethod (method, loc)));
11281 return CreateExpressionFactoryCall (ec, "Convert", args);
11284 protected override Expression DoResolve (ResolveContext ec)
11286 method.CheckObsoleteness (ec, source.Location);
11288 eclass = ExprClass.Value;
11292 public override void Emit (EmitContext ec)
11295 ec.MarkCallEntry (loc);
11296 ec.Emit (OpCodes.Call, method);
11299 public override void FlowAnalysis (FlowAnalysisContext fc)
11301 source.FlowAnalysis (fc);
11304 public override string GetSignatureForError ()
11306 return TypeManager.CSharpSignature (method);
11309 public override SLE.Expression MakeExpression (BuilderContext ctx)
11312 return base.MakeExpression (ctx);
11314 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11320 // Holds additional type specifiers like ?, *, []
11322 public class ComposedTypeSpecifier
11324 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11326 public readonly int Dimension;
11327 public readonly Location Location;
11329 public ComposedTypeSpecifier (int specifier, Location loc)
11331 this.Dimension = specifier;
11332 this.Location = loc;
11336 public bool IsNullable {
11338 return Dimension == -1;
11342 public bool IsPointer {
11344 return Dimension == -2;
11348 public ComposedTypeSpecifier Next { get; set; }
11352 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11354 return new ComposedTypeSpecifier (dimension, loc);
11357 public static ComposedTypeSpecifier CreateNullable (Location loc)
11359 return new ComposedTypeSpecifier (-1, loc);
11362 public static ComposedTypeSpecifier CreatePointer (Location loc)
11364 return new ComposedTypeSpecifier (-2, loc);
11367 public string GetSignatureForError ()
11372 ArrayContainer.GetPostfixSignature (Dimension);
11374 return Next != null ? s + Next.GetSignatureForError () : s;
11379 // This class is used to "construct" the type during a typecast
11380 // operation. Since the Type.GetType class in .NET can parse
11381 // the type specification, we just use this to construct the type
11382 // one bit at a time.
11384 public class ComposedCast : TypeExpr {
11385 FullNamedExpression left;
11386 ComposedTypeSpecifier spec;
11388 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11391 throw new ArgumentNullException ("spec");
11395 this.loc = left.Location;
11398 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11400 type = left.ResolveAsType (ec);
11404 eclass = ExprClass.Type;
11406 var single_spec = spec;
11408 if (single_spec.IsNullable) {
11409 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11413 single_spec = single_spec.Next;
11414 } else if (single_spec.IsPointer) {
11416 // Declared fields cannot have unmanaged check done before all types are defined
11418 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11421 var rc = ec as ResolveContext;
11422 if (rc?.CurrentIterator != null) {
11423 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11424 } else if (!ec.IsUnsafe) {
11425 UnsafeError (ec.Module.Compiler.Report, loc);
11429 type = PointerContainer.MakeType (ec.Module, type);
11430 single_spec = single_spec.Next;
11431 } while (single_spec != null && single_spec.IsPointer);
11434 if (single_spec != null && single_spec.Dimension > 0) {
11435 if (type.IsSpecialRuntimeType) {
11436 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11437 } else if (type.IsStatic) {
11438 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11439 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11440 type.GetSignatureForError ());
11442 MakeArray (ec.Module, single_spec);
11449 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11451 if (spec.Next != null)
11452 MakeArray (module, spec.Next);
11454 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11457 public override string GetSignatureForError ()
11459 return left.GetSignatureForError () + spec.GetSignatureForError ();
11462 public override object Accept (StructuralVisitor visitor)
11464 return visitor.Visit (this);
11468 class FixedBufferPtr : Expression
11470 readonly Expression array;
11472 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11474 this.type = array_type;
11475 this.array = array;
11479 public override bool ContainsEmitWithAwait ()
11481 throw new NotImplementedException ();
11484 public override Expression CreateExpressionTree (ResolveContext ec)
11486 Error_PointerInsideExpressionTree (ec);
11490 public override void Emit(EmitContext ec)
11495 protected override Expression DoResolve (ResolveContext ec)
11497 type = PointerContainer.MakeType (ec.Module, type);
11498 eclass = ExprClass.Value;
11505 // This class is used to represent the address of an array, used
11506 // only by the Fixed statement, this generates "&a [0]" construct
11507 // for fixed (char *pa = a)
11509 class ArrayPtr : FixedBufferPtr
11511 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11512 base (array, array_type, l)
11516 public override void Emit (EmitContext ec)
11521 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11526 // Encapsulates a conversion rules required for array indexes
11528 public class ArrayIndexCast : TypeCast
11530 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11531 : base (expr, returnType)
11533 if (expr.Type == returnType) // int -> int
11534 throw new ArgumentException ("unnecessary array index conversion");
11537 public override Expression CreateExpressionTree (ResolveContext ec)
11539 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11540 return base.CreateExpressionTree (ec);
11544 public override void Emit (EmitContext ec)
11548 switch (child.Type.BuiltinType) {
11549 case BuiltinTypeSpec.Type.UInt:
11550 ec.Emit (OpCodes.Conv_U);
11552 case BuiltinTypeSpec.Type.Long:
11553 ec.Emit (OpCodes.Conv_Ovf_I);
11555 case BuiltinTypeSpec.Type.ULong:
11556 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11559 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11565 // Implements the `stackalloc' keyword
11567 public class StackAlloc : Expression {
11572 public StackAlloc (Expression type, Expression count, Location l)
11575 this.count = count;
11579 public Expression TypeExpression {
11585 public Expression CountExpression {
11591 public override bool ContainsEmitWithAwait ()
11596 public override Expression CreateExpressionTree (ResolveContext ec)
11598 throw new NotSupportedException ("ET");
11601 protected override Expression DoResolve (ResolveContext ec)
11603 count = count.Resolve (ec);
11607 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11608 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11613 Constant c = count as Constant;
11614 if (c != null && c.IsNegative) {
11615 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11618 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11619 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11622 otype = texpr.ResolveAsType (ec);
11626 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11629 type = PointerContainer.MakeType (ec.Module, otype);
11630 eclass = ExprClass.Value;
11635 public override void Emit (EmitContext ec)
11637 int size = BuiltinTypeSpec.GetSize (otype);
11642 ec.Emit (OpCodes.Sizeof, otype);
11646 ec.Emit (OpCodes.Mul_Ovf_Un);
11647 ec.Emit (OpCodes.Localloc);
11650 protected override void CloneTo (CloneContext clonectx, Expression t)
11652 StackAlloc target = (StackAlloc) t;
11653 target.count = count.Clone (clonectx);
11654 target.texpr = texpr.Clone (clonectx);
11657 public override object Accept (StructuralVisitor visitor)
11659 return visitor.Visit (this);
11664 // An object initializer expression
11666 public class ElementInitializer : Assign
11668 public readonly string Name;
11670 public ElementInitializer (string name, Expression initializer, Location loc)
11671 : base (null, initializer, loc)
11676 public bool IsDictionaryInitializer {
11678 return Name == null;
11682 protected override void CloneTo (CloneContext clonectx, Expression t)
11684 ElementInitializer target = (ElementInitializer) t;
11685 target.source = source.Clone (clonectx);
11688 public override Expression CreateExpressionTree (ResolveContext ec)
11690 Arguments args = new Arguments (2);
11691 FieldExpr fe = target as FieldExpr;
11693 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11695 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11698 Expression arg_expr;
11699 var cinit = source as CollectionOrObjectInitializers;
11700 if (cinit == null) {
11702 arg_expr = source.CreateExpressionTree (ec);
11704 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11705 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11708 args.Add (new Argument (arg_expr));
11709 return CreateExpressionFactoryCall (ec, mname, args);
11712 protected override Expression DoResolve (ResolveContext ec)
11714 if (source == null)
11715 return EmptyExpressionStatement.Instance;
11717 if (!ResolveElement (ec))
11720 if (source is CollectionOrObjectInitializers) {
11721 target = target.Resolve (ec);
11722 if (target == null)
11725 Expression previous = ec.CurrentInitializerVariable;
11726 ec.CurrentInitializerVariable = target;
11727 source = source.Resolve (ec);
11728 ec.CurrentInitializerVariable = previous;
11729 if (source == null)
11732 eclass = source.eclass;
11733 type = source.Type;
11738 return base.DoResolve (ec);
11741 public override void EmitStatement (EmitContext ec)
11743 if (source is CollectionOrObjectInitializers)
11746 base.EmitStatement (ec);
11749 protected virtual bool ResolveElement (ResolveContext rc)
11751 var t = rc.CurrentInitializerVariable.Type;
11752 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11753 Arguments args = new Arguments (1);
11754 args.Add (new Argument (rc.CurrentInitializerVariable));
11755 target = new DynamicMemberBinder (Name, args, loc);
11757 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11758 if (member == null) {
11759 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11761 if (member != null) {
11762 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11763 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11768 if (member == null) {
11769 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11773 var me = member as MemberExpr;
11774 if (me is EventExpr) {
11775 me = me.ResolveMemberAccess (rc, null, null);
11776 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11777 rc.Report.Error (1913, loc,
11778 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11779 member.GetSignatureForError ());
11785 rc.Report.Error (1914, loc,
11786 "Static field or property `{0}' cannot be assigned in an object initializer",
11787 me.GetSignatureForError ());
11791 me.InstanceExpression = rc.CurrentInitializerVariable;
11799 // A collection initializer expression
11801 class CollectionElementInitializer : Invocation
11803 public class ElementInitializerArgument : Argument
11805 public ElementInitializerArgument (Expression e)
11811 sealed class AddMemberAccess : MemberAccess
11813 public AddMemberAccess (Expression expr, Location loc)
11814 : base (expr, "Add", loc)
11818 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11820 if (TypeManager.HasElementType (type))
11823 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11827 public CollectionElementInitializer (Expression argument)
11828 : base (null, new Arguments (1))
11830 base.arguments.Add (new ElementInitializerArgument (argument));
11831 this.loc = argument.Location;
11834 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11835 : base (null, new Arguments (arguments.Count))
11837 foreach (Expression e in arguments)
11838 base.arguments.Add (new ElementInitializerArgument (e));
11843 public CollectionElementInitializer (Location loc)
11844 : base (null, null)
11849 public override Expression CreateExpressionTree (ResolveContext ec)
11851 Arguments args = new Arguments (2);
11852 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11854 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11855 foreach (Argument a in arguments) {
11856 if (a.ArgType == Argument.AType.ExtensionType) {
11857 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11860 expr_initializers.Add (a.CreateExpressionTree (ec));
11863 args.Add (new Argument (new ArrayCreation (
11864 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11865 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11868 protected override void CloneTo (CloneContext clonectx, Expression t)
11870 CollectionElementInitializer target = (CollectionElementInitializer) t;
11871 if (arguments != null)
11872 target.arguments = arguments.Clone (clonectx);
11875 protected override Expression DoResolve (ResolveContext ec)
11877 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11879 return base.DoResolve (ec);
11883 class DictionaryElementInitializer : ElementInitializer
11885 readonly Arguments args;
11887 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11888 : base (null, initializer, loc)
11890 this.args = arguments;
11893 public override Expression CreateExpressionTree (ResolveContext ec)
11895 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11899 protected override bool ResolveElement (ResolveContext rc)
11901 var init = rc.CurrentInitializerVariable;
11902 var type = init.Type;
11904 if (type.IsArray) {
11905 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11909 if (type.IsPointer) {
11910 target = init.MakePointerAccess (rc, type, args);
11914 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11915 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11916 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11920 target = new IndexerExpr (indexers, type, init, args, loc);
11926 // A block of object or collection initializers
11928 public class CollectionOrObjectInitializers : ExpressionStatement
11930 IList<Expression> initializers;
11931 bool is_collection_initialization;
11933 public CollectionOrObjectInitializers (Location loc)
11934 : this (new Expression[0], loc)
11938 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11940 this.initializers = initializers;
11944 public IList<Expression> Initializers {
11946 return initializers;
11950 public bool IsEmpty {
11952 return initializers.Count == 0;
11956 public bool IsCollectionInitializer {
11958 return is_collection_initialization;
11962 protected override void CloneTo (CloneContext clonectx, Expression target)
11964 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11966 t.initializers = new List<Expression> (initializers.Count);
11967 foreach (var e in initializers)
11968 t.initializers.Add (e.Clone (clonectx));
11971 public override bool ContainsEmitWithAwait ()
11973 foreach (var e in initializers) {
11974 if (e.ContainsEmitWithAwait ())
11981 public override Expression CreateExpressionTree (ResolveContext ec)
11983 return CreateExpressionTree (ec, false);
11986 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11988 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11989 foreach (Expression e in initializers) {
11990 Expression expr = e.CreateExpressionTree (ec);
11992 expr_initializers.Add (expr);
11996 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11998 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12001 protected override Expression DoResolve (ResolveContext ec)
12003 List<string> element_names = null;
12004 for (int i = 0; i < initializers.Count; ++i) {
12005 Expression initializer = initializers [i];
12006 ElementInitializer element_initializer = initializer as ElementInitializer;
12009 if (element_initializer != null) {
12010 element_names = new List<string> (initializers.Count);
12011 if (!element_initializer.IsDictionaryInitializer)
12012 element_names.Add (element_initializer.Name);
12013 } else if (initializer is CompletingExpression) {
12014 initializer.Resolve (ec);
12015 throw new InternalErrorException ("This line should never be reached");
12017 var t = ec.CurrentInitializerVariable.Type;
12018 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12019 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12020 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12021 "object initializer because type `{1}' does not implement `{2}' interface",
12022 ec.CurrentInitializerVariable.GetSignatureForError (),
12023 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12024 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12027 is_collection_initialization = true;
12030 if (is_collection_initialization != (element_initializer == null)) {
12031 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12032 is_collection_initialization ? "collection initializer" : "object initializer");
12036 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12037 if (element_names.Contains (element_initializer.Name)) {
12038 ec.Report.Error (1912, element_initializer.Location,
12039 "An object initializer includes more than one member `{0}' initialization",
12040 element_initializer.Name);
12042 element_names.Add (element_initializer.Name);
12047 Expression e = initializer.Resolve (ec);
12048 if (e == EmptyExpressionStatement.Instance)
12049 initializers.RemoveAt (i--);
12051 initializers [i] = e;
12054 type = ec.CurrentInitializerVariable.Type;
12055 if (is_collection_initialization) {
12056 if (TypeManager.HasElementType (type)) {
12057 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12058 type.GetSignatureForError ());
12062 eclass = ExprClass.Variable;
12066 public override void Emit (EmitContext ec)
12068 EmitStatement (ec);
12071 public override void EmitStatement (EmitContext ec)
12073 foreach (ExpressionStatement e in initializers) {
12074 // TODO: need location region
12075 ec.Mark (e.Location);
12076 e.EmitStatement (ec);
12080 public override void FlowAnalysis (FlowAnalysisContext fc)
12082 foreach (var initializer in initializers) {
12083 if (initializer != null)
12084 initializer.FlowAnalysis (fc);
12090 // New expression with element/object initializers
12092 public class NewInitialize : New
12095 // This class serves as a proxy for variable initializer target instances.
12096 // A real variable is assigned later when we resolve left side of an
12099 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12101 NewInitialize new_instance;
12103 public InitializerTargetExpression (NewInitialize newInstance)
12105 this.type = newInstance.type;
12106 this.loc = newInstance.loc;
12107 this.eclass = newInstance.eclass;
12108 this.new_instance = newInstance;
12111 public override bool ContainsEmitWithAwait ()
12116 public override Expression CreateExpressionTree (ResolveContext ec)
12118 // Should not be reached
12119 throw new NotSupportedException ("ET");
12122 protected override Expression DoResolve (ResolveContext ec)
12127 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12132 public override void Emit (EmitContext ec)
12134 Expression e = (Expression) new_instance.instance;
12138 public override Expression EmitToField (EmitContext ec)
12140 return (Expression) new_instance.instance;
12143 #region IMemoryLocation Members
12145 public void AddressOf (EmitContext ec, AddressOp mode)
12147 new_instance.instance.AddressOf (ec, mode);
12153 CollectionOrObjectInitializers initializers;
12154 IMemoryLocation instance;
12155 DynamicExpressionStatement dynamic;
12157 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12158 : base (requested_type, arguments, l)
12160 this.initializers = initializers;
12163 public CollectionOrObjectInitializers Initializers {
12165 return initializers;
12169 protected override void CloneTo (CloneContext clonectx, Expression t)
12171 base.CloneTo (clonectx, t);
12173 NewInitialize target = (NewInitialize) t;
12174 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12177 public override bool ContainsEmitWithAwait ()
12179 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12182 public override Expression CreateExpressionTree (ResolveContext ec)
12184 Arguments args = new Arguments (2);
12185 args.Add (new Argument (base.CreateExpressionTree (ec)));
12186 if (!initializers.IsEmpty)
12187 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12189 return CreateExpressionFactoryCall (ec,
12190 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12194 protected override Expression DoResolve (ResolveContext rc)
12196 Expression e = base.DoResolve (rc);
12200 if (type.IsDelegate) {
12201 rc.Report.Error (1958, Initializers.Location,
12202 "Object and collection initializers cannot be used to instantiate a delegate");
12205 Expression previous = rc.CurrentInitializerVariable;
12206 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12207 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12208 initializers.Resolve (rc);
12210 rc.CurrentInitializerVariable = previous;
12212 dynamic = e as DynamicExpressionStatement;
12213 if (dynamic != null)
12219 public override void Emit (EmitContext ec)
12221 if (!CanEmitOptimizedLocalTarget (ec)) {
12222 var fe = ec.GetTemporaryField (type);
12224 if (!Emit (ec, fe))
12233 public override bool Emit (EmitContext ec, IMemoryLocation target)
12236 // Expression is initialized into temporary target then moved
12237 // to real one for atomicity
12239 IMemoryLocation temp_target = target;
12241 LocalTemporary temp = null;
12242 bool by_ref = false;
12243 if (!initializers.IsEmpty) {
12244 temp_target = target as LocalTemporary;
12245 if (temp_target == null)
12246 temp_target = target as StackFieldExpr;
12248 if (temp_target == null) {
12249 var vr = target as VariableReference;
12250 if (vr != null && vr.IsRef) {
12256 if (temp_target == null)
12257 temp_target = temp = new LocalTemporary (type);
12260 bool left_on_stack;
12261 if (dynamic != null) {
12263 left_on_stack = true;
12265 left_on_stack = base.Emit (ec, temp_target);
12268 if (initializers.IsEmpty)
12269 return left_on_stack;
12271 StackFieldExpr sf = null;
12273 // Move a new instance (reference-type) to local temporary variable
12274 if (left_on_stack) {
12276 temp_target = temp = new LocalTemporary (type);
12282 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12284 throw new NotImplementedException ();
12286 sf = ec.GetTemporaryField (type);
12287 sf.AutomaticallyReuse = false;
12288 sf.EmitAssign (ec, temp, false, false);
12291 left_on_stack = false;
12295 instance = temp_target;
12297 initializers.Emit (ec);
12299 ((Expression)temp_target).Emit (ec);
12305 sf.PrepareCleanup (ec);
12310 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12312 return !(method == null && TypeSpec.IsValueType (type) &&
12313 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12314 initializers.ContainsEmitWithAwait ());
12317 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12319 instance = base.EmitAddressOf (ec, Mode);
12321 if (!initializers.IsEmpty)
12322 initializers.Emit (ec);
12327 public override void FlowAnalysis (FlowAnalysisContext fc)
12329 base.FlowAnalysis (fc);
12330 initializers.FlowAnalysis (fc);
12333 public override object Accept (StructuralVisitor visitor)
12335 return visitor.Visit (this);
12339 public class NewAnonymousType : New
12341 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12343 List<AnonymousTypeParameter> parameters;
12344 readonly TypeContainer parent;
12345 AnonymousTypeClass anonymous_type;
12347 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12348 : base (null, null, loc)
12350 this.parameters = parameters;
12351 this.parent = parent;
12354 public List<AnonymousTypeParameter> Parameters {
12356 return this.parameters;
12360 protected override void CloneTo (CloneContext clonectx, Expression target)
12362 if (parameters == null)
12365 NewAnonymousType t = (NewAnonymousType) target;
12366 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12367 foreach (AnonymousTypeParameter atp in parameters)
12368 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12371 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12373 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12377 type = AnonymousTypeClass.Create (parent, parameters, loc);
12381 int errors = ec.Report.Errors;
12382 type.CreateContainer ();
12383 type.DefineContainer ();
12384 type.ExpandBaseInterfaces ();
12386 if ((ec.Report.Errors - errors) == 0) {
12387 parent.Module.AddAnonymousType (type);
12388 type.PrepareEmit ();
12394 public override Expression CreateExpressionTree (ResolveContext ec)
12396 if (parameters == null)
12397 return base.CreateExpressionTree (ec);
12399 var init = new ArrayInitializer (parameters.Count, loc);
12400 foreach (var m in anonymous_type.Members) {
12401 var p = m as Property;
12403 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12406 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12407 foreach (Argument a in arguments)
12408 ctor_args.Add (a.CreateExpressionTree (ec));
12410 Arguments args = new Arguments (3);
12411 args.Add (new Argument (new TypeOfMethod (method, loc)));
12412 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12413 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12415 return CreateExpressionFactoryCall (ec, "New", args);
12418 protected override Expression DoResolve (ResolveContext ec)
12420 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12421 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12425 if (parameters == null) {
12426 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12427 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12428 return base.DoResolve (ec);
12431 bool error = false;
12432 arguments = new Arguments (parameters.Count);
12433 var t_args = new TypeSpec [parameters.Count];
12434 for (int i = 0; i < parameters.Count; ++i) {
12435 Expression e = parameters [i].Resolve (ec);
12441 arguments.Add (new Argument (e));
12442 t_args [i] = e.Type;
12448 anonymous_type = CreateAnonymousType (ec, parameters);
12449 if (anonymous_type == null)
12452 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12453 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12454 eclass = ExprClass.Value;
12458 public override object Accept (StructuralVisitor visitor)
12460 return visitor.Visit (this);
12464 public class AnonymousTypeParameter : ShimExpression
12466 public readonly string Name;
12468 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12469 : base (initializer)
12475 public AnonymousTypeParameter (Parameter parameter)
12476 : base (new SimpleName (parameter.Name, parameter.Location))
12478 this.Name = parameter.Name;
12479 this.loc = parameter.Location;
12482 public override bool Equals (object o)
12484 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12485 return other != null && Name == other.Name;
12488 public override int GetHashCode ()
12490 return Name.GetHashCode ();
12493 protected override Expression DoResolve (ResolveContext ec)
12495 Expression e = expr.Resolve (ec);
12499 if (e.eclass == ExprClass.MethodGroup) {
12500 Error_InvalidInitializer (ec, e.ExprClassName);
12505 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12506 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12513 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12515 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12516 Name, initializer);
12520 public class CatchFilterExpression : BooleanExpression
12522 public CatchFilterExpression (Expression expr, Location loc)
12529 public class InterpolatedString : Expression
12531 readonly StringLiteral start, end;
12532 List<Expression> interpolations;
12533 Arguments arguments;
12535 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12537 this.start = start;
12539 this.interpolations = interpolations;
12540 loc = start.Location;
12543 protected override void CloneTo (CloneContext clonectx, Expression t)
12545 InterpolatedString target = (InterpolatedString) t;
12547 if (interpolations != null) {
12548 target.interpolations = new List<Expression> ();
12549 foreach (var interpolation in interpolations) {
12550 target.interpolations.Add (interpolation.Clone (clonectx));
12555 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12557 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12558 if (factory == null)
12561 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12562 var res = new Invocation (ma, arguments).Resolve (rc);
12563 if (res != null && res.Type != type)
12564 res = Convert.ExplicitConversion (rc, res, type, loc);
12569 public override bool ContainsEmitWithAwait ()
12571 if (interpolations == null)
12574 foreach (var expr in interpolations) {
12575 if (expr.ContainsEmitWithAwait ())
12582 public override Expression CreateExpressionTree (ResolveContext rc)
12584 var best = ResolveBestFormatOverload (rc);
12588 Expression instance = new NullLiteral (loc);
12589 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12590 return CreateExpressionFactoryCall (rc, "Call", args);
12593 protected override Expression DoResolve (ResolveContext rc)
12597 if (interpolations == null) {
12599 arguments = new Arguments (1);
12601 arguments = new Arguments (interpolations.Count);
12603 var sb = new StringBuilder (start.Value);
12604 for (int i = 0; i < interpolations.Count; ++i) {
12606 sb.Append ('{').Append (i / 2);
12607 var isi = (InterpolatedStringInsert)interpolations [i];
12608 if (isi.Alignment != null) {
12610 var value = isi.ResolveAligment (rc);
12612 sb.Append (value.Value);
12615 if (isi.Format != null) {
12617 sb.Append (isi.Format);
12621 arguments.Add (new Argument (isi.Resolve (rc)));
12623 sb.Append (((StringLiteral)interpolations [i]).Value);
12627 sb.Append (end.Value);
12628 str = sb.ToString ();
12631 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12633 eclass = ExprClass.Value;
12634 type = rc.BuiltinTypes.String;
12638 public override void Emit (EmitContext ec)
12640 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12641 if (interpolations == null) {
12642 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12643 if (str != start.Value)
12644 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12651 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12655 var ca = new CallEmitter ();
12656 ca.Emit (ec, best, arguments, loc);
12659 public override void FlowAnalysis (FlowAnalysisContext fc)
12661 if (interpolations != null) {
12662 foreach (var expr in interpolations) {
12663 expr.FlowAnalysis (fc);
12668 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12670 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12671 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12672 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12676 public class InterpolatedStringInsert : CompositeExpression
12678 public InterpolatedStringInsert (Expression expr)
12683 public Expression Alignment { get; set; }
12684 public string Format { get; set; }
12686 protected override void CloneTo (CloneContext clonectx, Expression t)
12688 var target = (InterpolatedStringInsert)t;
12689 target.expr = expr.Clone (clonectx);
12690 if (Alignment != null)
12691 target.Alignment = Alignment.Clone (clonectx);
12694 protected override Expression DoResolve (ResolveContext rc)
12696 var expr = base.DoResolve (rc);
12701 // For better error reporting, assumes the built-in implementation uses object
12704 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12707 public override void FlowAnalysis (FlowAnalysisContext fc)
12709 Child.FlowAnalysis (fc);
12712 public int? ResolveAligment (ResolveContext rc)
12714 var c = Alignment.ResolveLabelConstant (rc);
12718 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12722 var value = (int) c.GetValueAsLong ();
12723 if (value > 32767 || value < -32767) {
12724 rc.Report.Warning (8094, 1, Alignment.Location,
12725 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");