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 bool conditional_access_receiver;
106 public ParenthesizedExpression (Expression expr, Location loc)
112 void ResolveConditionalAccessReceiver (ResolveContext rc)
114 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
115 conditional_access_receiver = true;
119 protected override Expression DoResolve (ResolveContext rc)
121 Expression res = null;
123 ResolveConditionalAccessReceiver (rc);
124 if (conditional_access_receiver) {
125 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
126 res = expr.Resolve (rc);
129 res = expr.Resolve (rc);
132 var constant = res as Constant;
133 if (constant != null && constant.IsLiteral) {
134 if (res is NullLiteral)
137 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
140 if (conditional_access_receiver) {
142 type = LiftMemberType (rc, res.Type);
143 eclass = expr.eclass;
150 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
152 return expr.DoResolveLValue (ec, right_side);
155 public override object Accept (StructuralVisitor visitor)
157 return visitor.Visit (this);
160 public override void Emit (EmitContext ec)
162 if (!conditional_access_receiver)
165 var prev = ec.ConditionalAccess;
166 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
168 ec.CloseConditionalAccess (type.IsNullableType ? type : null);
169 ec.ConditionalAccess = prev;
172 public override bool HasConditionalAccess ()
179 // Unary implements unary expressions.
181 public class Unary : Expression
183 public enum Operator : byte {
184 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
188 public readonly Operator Oper;
189 public Expression Expr;
190 ConvCast.Mode enum_conversion;
192 public Unary (Operator op, Expression expr, Location loc)
200 // This routine will attempt to simplify the unary expression when the
201 // argument is a constant.
203 Constant TryReduceConstant (ResolveContext ec, Constant constant)
207 while (e is EmptyConstantCast)
208 e = ((EmptyConstantCast) e).child;
210 if (e is SideEffectConstant) {
211 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
212 return r == null ? null : new SideEffectConstant (r, e, r.Location);
215 TypeSpec expr_type = e.Type;
218 case Operator.UnaryPlus:
219 // Unary numeric promotions
220 switch (expr_type.BuiltinType) {
221 case BuiltinTypeSpec.Type.Byte:
222 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
223 case BuiltinTypeSpec.Type.SByte:
224 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
225 case BuiltinTypeSpec.Type.Short:
226 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
227 case BuiltinTypeSpec.Type.UShort:
228 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
229 case BuiltinTypeSpec.Type.Char:
230 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
232 // Predefined operators
233 case BuiltinTypeSpec.Type.Int:
234 case BuiltinTypeSpec.Type.UInt:
235 case BuiltinTypeSpec.Type.Long:
236 case BuiltinTypeSpec.Type.ULong:
237 case BuiltinTypeSpec.Type.Float:
238 case BuiltinTypeSpec.Type.Double:
239 case BuiltinTypeSpec.Type.Decimal:
245 case Operator.UnaryNegation:
246 // Unary numeric promotions
247 switch (expr_type.BuiltinType) {
248 case BuiltinTypeSpec.Type.Byte:
249 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
250 case BuiltinTypeSpec.Type.SByte:
251 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
252 case BuiltinTypeSpec.Type.Short:
253 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
254 case BuiltinTypeSpec.Type.UShort:
255 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
256 case BuiltinTypeSpec.Type.Char:
257 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
259 // Predefined operators
260 case BuiltinTypeSpec.Type.Int:
261 int ivalue = ((IntConstant) e).Value;
262 if (ivalue == int.MinValue) {
263 if (ec.ConstantCheckState) {
264 ConstantFold.Error_CompileTimeOverflow (ec, loc);
269 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
271 case BuiltinTypeSpec.Type.Long:
272 long lvalue = ((LongConstant) e).Value;
273 if (lvalue == long.MinValue) {
274 if (ec.ConstantCheckState) {
275 ConstantFold.Error_CompileTimeOverflow (ec, loc);
280 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
282 case BuiltinTypeSpec.Type.UInt:
283 UIntLiteral uil = constant as UIntLiteral;
285 if (uil.Value == int.MaxValue + (uint) 1)
286 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
287 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
289 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
292 case BuiltinTypeSpec.Type.ULong:
293 ULongLiteral ull = constant as ULongLiteral;
294 if (ull != null && ull.Value == 9223372036854775808)
295 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
298 case BuiltinTypeSpec.Type.Float:
299 FloatLiteral fl = constant as FloatLiteral;
300 // For better error reporting
302 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
304 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
306 case BuiltinTypeSpec.Type.Double:
307 DoubleLiteral dl = constant as DoubleLiteral;
308 // For better error reporting
310 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
312 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.Decimal:
315 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
320 case Operator.LogicalNot:
321 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
324 bool b = (bool)e.GetValue ();
325 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
327 case Operator.OnesComplement:
328 // Unary numeric promotions
329 switch (expr_type.BuiltinType) {
330 case BuiltinTypeSpec.Type.Byte:
331 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
332 case BuiltinTypeSpec.Type.SByte:
333 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
334 case BuiltinTypeSpec.Type.Short:
335 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
336 case BuiltinTypeSpec.Type.UShort:
337 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
338 case BuiltinTypeSpec.Type.Char:
339 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
341 // Predefined operators
342 case BuiltinTypeSpec.Type.Int:
343 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
344 case BuiltinTypeSpec.Type.UInt:
345 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
346 case BuiltinTypeSpec.Type.Long:
347 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
348 case BuiltinTypeSpec.Type.ULong:
349 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
351 if (e is EnumConstant) {
352 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
355 // Numeric promotion upgraded types to int but for enum constant
356 // original underlying constant type is needed
358 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
359 int v = ((IntConstant) res).Value;
360 switch (((EnumConstant) e).Child.Type.BuiltinType) {
361 case BuiltinTypeSpec.Type.UShort:
362 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
364 case BuiltinTypeSpec.Type.Short:
365 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
367 case BuiltinTypeSpec.Type.Byte:
368 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
370 case BuiltinTypeSpec.Type.SByte:
371 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
376 res = new EnumConstant (res, expr_type);
382 throw new Exception ("Can not constant fold: " + Oper.ToString());
385 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
387 eclass = ExprClass.Value;
389 TypeSpec expr_type = expr.Type;
390 Expression best_expr;
392 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
395 // Primitive types first
397 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
398 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
399 if (best_expr == null)
402 type = best_expr.Type;
408 // E operator ~(E x);
410 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
411 return ResolveEnumOperator (ec, expr, predefined);
413 return ResolveUserType (ec, expr, predefined);
416 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
418 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
419 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
420 if (best_expr == null)
424 enum_conversion = Binary.GetEnumResultCast (underlying_type);
426 return EmptyCast.Create (this, type);
429 public override bool ContainsEmitWithAwait ()
431 return Expr.ContainsEmitWithAwait ();
434 public override Expression CreateExpressionTree (ResolveContext ec)
436 return CreateExpressionTree (ec, null);
439 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
443 case Operator.AddressOf:
444 Error_PointerInsideExpressionTree (ec);
446 case Operator.UnaryNegation:
447 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
448 method_name = "NegateChecked";
450 method_name = "Negate";
452 case Operator.OnesComplement:
453 case Operator.LogicalNot:
456 case Operator.UnaryPlus:
457 method_name = "UnaryPlus";
460 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
463 Arguments args = new Arguments (2);
464 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
466 args.Add (new Argument (user_op));
468 return CreateExpressionFactoryCall (ec, method_name, args);
471 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
473 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
476 // 7.6.1 Unary plus operator
478 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
479 types.Int, types.UInt,
480 types.Long, types.ULong,
481 types.Float, types.Double,
486 // 7.6.2 Unary minus operator
488 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
489 types.Int, types.Long,
490 types.Float, types.Double,
495 // 7.6.3 Logical negation operator
497 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
502 // 7.6.4 Bitwise complement operator
504 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
505 types.Int, types.UInt,
506 types.Long, types.ULong
509 return predefined_operators;
513 // Unary numeric promotions
515 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
517 TypeSpec expr_type = expr.Type;
518 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
519 switch (expr_type.BuiltinType) {
520 case BuiltinTypeSpec.Type.Byte:
521 case BuiltinTypeSpec.Type.SByte:
522 case BuiltinTypeSpec.Type.Short:
523 case BuiltinTypeSpec.Type.UShort:
524 case BuiltinTypeSpec.Type.Char:
525 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
529 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
530 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
535 protected override Expression DoResolve (ResolveContext ec)
537 if (Oper == Operator.AddressOf) {
538 return ResolveAddressOf (ec);
541 Expr = Expr.Resolve (ec);
545 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
546 Arguments args = new Arguments (1);
547 args.Add (new Argument (Expr));
548 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
551 if (Expr.Type.IsNullableType)
552 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
555 // Attempt to use a constant folding operation.
557 Constant cexpr = Expr as Constant;
559 cexpr = TryReduceConstant (ec, cexpr);
564 Expression expr = ResolveOperator (ec, Expr);
566 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
569 // Reduce unary operator on predefined types
571 if (expr == this && Oper == Operator.UnaryPlus)
577 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
582 public override void Emit (EmitContext ec)
584 EmitOperator (ec, type);
587 protected void EmitOperator (EmitContext ec, TypeSpec type)
590 case Operator.UnaryPlus:
594 case Operator.UnaryNegation:
595 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
596 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
597 Expr = Expr.EmitToField (ec);
600 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
601 ec.Emit (OpCodes.Conv_U8);
603 ec.Emit (OpCodes.Sub_Ovf);
606 ec.Emit (OpCodes.Neg);
611 case Operator.LogicalNot:
614 ec.Emit (OpCodes.Ceq);
617 case Operator.OnesComplement:
619 ec.Emit (OpCodes.Not);
622 case Operator.AddressOf:
623 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
627 throw new Exception ("This should not happen: Operator = "
632 // Same trick as in Binary expression
634 if (enum_conversion != 0) {
635 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
636 ConvCast.Emit (ec, enum_conversion);
641 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
643 if (Oper == Operator.LogicalNot)
644 Expr.EmitBranchable (ec, target, !on_true);
646 base.EmitBranchable (ec, target, on_true);
649 public override void EmitSideEffect (EmitContext ec)
651 Expr.EmitSideEffect (ec);
654 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
656 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
657 oper, type.GetSignatureForError ());
660 public override void FlowAnalysis (FlowAnalysisContext fc)
662 FlowAnalysis (fc, false);
665 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
667 FlowAnalysis (fc, true);
670 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
672 if (Oper == Operator.AddressOf) {
673 var vr = Expr as VariableReference;
674 if (vr != null && vr.VariableInfo != null)
675 fc.SetVariableAssigned (vr.VariableInfo);
680 if (Oper == Operator.LogicalNot && conditional) {
681 Expr.FlowAnalysisConditional (fc);
683 var temp = fc.DefiniteAssignmentOnTrue;
684 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
685 fc.DefiniteAssignmentOnFalse = temp;
687 Expr.FlowAnalysis (fc);
692 // Converts operator to System.Linq.Expressions.ExpressionType enum name
694 string GetOperatorExpressionTypeName ()
697 case Operator.OnesComplement:
698 return "OnesComplement";
699 case Operator.LogicalNot:
701 case Operator.UnaryNegation:
703 case Operator.UnaryPlus:
706 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
710 static bool IsFloat (TypeSpec t)
712 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
716 // Returns a stringified representation of the Operator
718 public static string OperName (Operator oper)
721 case Operator.UnaryPlus:
723 case Operator.UnaryNegation:
725 case Operator.LogicalNot:
727 case Operator.OnesComplement:
729 case Operator.AddressOf:
733 throw new NotImplementedException (oper.ToString ());
736 public override SLE.Expression MakeExpression (BuilderContext ctx)
738 var expr = Expr.MakeExpression (ctx);
739 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
742 case Operator.UnaryNegation:
743 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
744 case Operator.LogicalNot:
745 return SLE.Expression.Not (expr);
746 case Operator.OnesComplement:
747 return SLE.Expression.OnesComplement (expr);
749 throw new NotImplementedException (Oper.ToString ());
753 Expression ResolveAddressOf (ResolveContext ec)
756 UnsafeError (ec, loc);
758 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
759 if (Expr == null || Expr.eclass != ExprClass.Variable) {
760 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
764 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
768 IVariableReference vr = Expr as IVariableReference;
771 is_fixed = vr.IsFixed;
772 vr.SetHasAddressTaken ();
775 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
778 IFixedExpression fe = Expr as IFixedExpression;
779 is_fixed = fe != null && fe.IsFixed;
782 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
783 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
786 type = PointerContainer.MakeType (ec.Module, Expr.Type);
787 eclass = ExprClass.Value;
791 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
793 expr = DoNumericPromotion (rc, Oper, expr);
794 TypeSpec expr_type = expr.Type;
795 foreach (TypeSpec t in predefined) {
803 // Perform user-operator overload resolution
805 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
807 CSharp.Operator.OpType op_type;
809 case Operator.LogicalNot:
810 op_type = CSharp.Operator.OpType.LogicalNot; break;
811 case Operator.OnesComplement:
812 op_type = CSharp.Operator.OpType.OnesComplement; break;
813 case Operator.UnaryNegation:
814 op_type = CSharp.Operator.OpType.UnaryNegation; break;
815 case Operator.UnaryPlus:
816 op_type = CSharp.Operator.OpType.UnaryPlus; break;
818 throw new InternalErrorException (Oper.ToString ());
821 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
825 Arguments args = new Arguments (1);
826 args.Add (new Argument (expr));
828 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
829 var oper = res.ResolveOperator (ec, ref args);
834 Expr = args [0].Expr;
835 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
839 // Unary user type overload resolution
841 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
843 Expression best_expr = ResolveUserOperator (ec, expr);
844 if (best_expr != null)
847 foreach (TypeSpec t in predefined) {
848 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
849 if (oper_expr == null)
852 if (oper_expr == ErrorExpression.Instance)
856 // decimal type is predefined but has user-operators
858 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
859 oper_expr = ResolveUserType (ec, oper_expr, predefined);
861 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
863 if (oper_expr == null)
866 if (best_expr == null) {
867 best_expr = oper_expr;
871 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
873 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
874 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
876 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
883 best_expr = oper_expr;
886 if (best_expr == null)
890 // HACK: Decimal user-operator is included in standard operators
892 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
896 type = best_expr.Type;
900 protected override void CloneTo (CloneContext clonectx, Expression t)
902 Unary target = (Unary) t;
904 target.Expr = Expr.Clone (clonectx);
907 public override object Accept (StructuralVisitor visitor)
909 return visitor.Visit (this);
915 // Unary operators are turned into Indirection expressions
916 // after semantic analysis (this is so we can take the address
917 // of an indirection).
919 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
921 LocalTemporary temporary;
924 public Indirection (Expression expr, Location l)
930 public Expression Expr {
936 public bool IsFixed {
940 public override Location StartLocation {
942 return expr.StartLocation;
946 protected override void CloneTo (CloneContext clonectx, Expression t)
948 Indirection target = (Indirection) t;
949 target.expr = expr.Clone (clonectx);
952 public override bool ContainsEmitWithAwait ()
954 throw new NotImplementedException ();
957 public override Expression CreateExpressionTree (ResolveContext ec)
959 Error_PointerInsideExpressionTree (ec);
963 public override void Emit (EmitContext ec)
968 ec.EmitLoadFromPtr (Type);
971 public void Emit (EmitContext ec, bool leave_copy)
975 ec.Emit (OpCodes.Dup);
976 temporary = new LocalTemporary (expr.Type);
977 temporary.Store (ec);
981 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
983 prepared = isCompound;
988 ec.Emit (OpCodes.Dup);
992 ec.Emit (OpCodes.Dup);
993 temporary = new LocalTemporary (source.Type);
994 temporary.Store (ec);
997 ec.EmitStoreFromPtr (type);
999 if (temporary != null) {
1000 temporary.Emit (ec);
1001 temporary.Release (ec);
1005 public void AddressOf (EmitContext ec, AddressOp Mode)
1010 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1012 return DoResolve (ec);
1015 protected override Expression DoResolve (ResolveContext ec)
1017 expr = expr.Resolve (ec);
1022 UnsafeError (ec, loc);
1024 var pc = expr.Type as PointerContainer;
1027 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1033 if (type.Kind == MemberKind.Void) {
1034 Error_VoidPointerOperation (ec);
1038 eclass = ExprClass.Variable;
1042 public override object Accept (StructuralVisitor visitor)
1044 return visitor.Visit (this);
1049 /// Unary Mutator expressions (pre and post ++ and --)
1053 /// UnaryMutator implements ++ and -- expressions. It derives from
1054 /// ExpressionStatement becuase the pre/post increment/decrement
1055 /// operators can be used in a statement context.
1057 /// FIXME: Idea, we could split this up in two classes, one simpler
1058 /// for the common case, and one with the extra fields for more complex
1059 /// classes (indexers require temporary access; overloaded require method)
1062 public class UnaryMutator : ExpressionStatement
1064 class DynamicPostMutator : Expression, IAssignMethod
1066 LocalTemporary temp;
1069 public DynamicPostMutator (Expression expr)
1072 this.type = expr.Type;
1073 this.loc = expr.Location;
1076 public override Expression CreateExpressionTree (ResolveContext ec)
1078 throw new NotImplementedException ("ET");
1081 protected override Expression DoResolve (ResolveContext rc)
1083 eclass = expr.eclass;
1087 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1089 expr.DoResolveLValue (ec, right_side);
1090 return DoResolve (ec);
1093 public override void Emit (EmitContext ec)
1098 public void Emit (EmitContext ec, bool leave_copy)
1100 throw new NotImplementedException ();
1104 // Emits target assignment using unmodified source value
1106 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1109 // Allocate temporary variable to keep original value before it's modified
1111 temp = new LocalTemporary (type);
1115 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1126 public enum Mode : byte {
1133 PreDecrement = IsDecrement,
1134 PostIncrement = IsPost,
1135 PostDecrement = IsPost | IsDecrement
1139 bool is_expr, recurse;
1141 protected Expression expr;
1143 // Holds the real operation
1144 Expression operation;
1146 public UnaryMutator (Mode m, Expression e, Location loc)
1153 public Mode UnaryMutatorMode {
1159 public Expression Expr {
1165 public override Location StartLocation {
1167 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1171 public override bool ContainsEmitWithAwait ()
1173 return expr.ContainsEmitWithAwait ();
1176 public override Expression CreateExpressionTree (ResolveContext ec)
1178 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1181 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1184 // Predefined ++ and -- operators exist for the following types:
1185 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1187 return new TypeSpec[] {
1203 protected override Expression DoResolve (ResolveContext ec)
1205 expr = expr.Resolve (ec);
1207 if (expr == null || expr.Type == InternalType.ErrorType)
1210 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1212 // Handle postfix unary operators using local
1213 // temporary variable
1215 if ((mode & Mode.IsPost) != 0)
1216 expr = new DynamicPostMutator (expr);
1218 Arguments args = new Arguments (1);
1219 args.Add (new Argument (expr));
1220 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1223 if (expr.Type.IsNullableType)
1224 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1226 return DoResolveOperation (ec);
1229 protected Expression DoResolveOperation (ResolveContext ec)
1231 eclass = ExprClass.Value;
1234 if (expr is RuntimeValueExpression) {
1237 // Use itself at the top of the stack
1238 operation = new EmptyExpression (type);
1242 // The operand of the prefix/postfix increment decrement operators
1243 // should be an expression that is classified as a variable,
1244 // a property access or an indexer access
1246 // TODO: Move to parser, expr is ATypeNameExpression
1247 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1248 expr = expr.ResolveLValue (ec, expr);
1250 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1254 // Step 1: Try to find a user operator, it has priority over predefined ones
1256 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1257 var methods = MemberCache.GetUserOperator (type, user_op, false);
1259 if (methods != null) {
1260 Arguments args = new Arguments (1);
1261 args.Add (new Argument (expr));
1263 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1264 var method = res.ResolveOperator (ec, ref args);
1268 args[0].Expr = operation;
1269 operation = new UserOperatorCall (method, args, null, loc);
1270 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1275 // Step 2: Try predefined types
1278 Expression source = null;
1279 bool primitive_type;
1282 // Predefined without user conversion first for speed-up
1284 // Predefined ++ and -- operators exist for the following types:
1285 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1287 switch (type.BuiltinType) {
1288 case BuiltinTypeSpec.Type.Byte:
1289 case BuiltinTypeSpec.Type.SByte:
1290 case BuiltinTypeSpec.Type.Short:
1291 case BuiltinTypeSpec.Type.UShort:
1292 case BuiltinTypeSpec.Type.Int:
1293 case BuiltinTypeSpec.Type.UInt:
1294 case BuiltinTypeSpec.Type.Long:
1295 case BuiltinTypeSpec.Type.ULong:
1296 case BuiltinTypeSpec.Type.Char:
1297 case BuiltinTypeSpec.Type.Float:
1298 case BuiltinTypeSpec.Type.Double:
1299 case BuiltinTypeSpec.Type.Decimal:
1301 primitive_type = true;
1304 primitive_type = false;
1306 // ++/-- on pointer variables of all types except void*
1307 if (type.IsPointer) {
1308 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1309 Error_VoidPointerOperation (ec);
1315 Expression best_source = null;
1316 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1317 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1319 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1323 if (best_source == null) {
1324 best_source = source;
1328 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1333 best_source = source;
1337 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1341 source = best_source;
1344 // ++/-- on enum types
1345 if (source == null && type.IsEnum)
1348 if (source == null) {
1349 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1356 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1357 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1358 operation = new Binary (op, source, one);
1359 operation = operation.Resolve (ec);
1360 if (operation == null)
1361 throw new NotImplementedException ("should not be reached");
1363 if (operation.Type != type) {
1365 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1367 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1373 void EmitCode (EmitContext ec, bool is_expr)
1376 this.is_expr = is_expr;
1377 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1380 public override void Emit (EmitContext ec)
1383 // We use recurse to allow ourselfs to be the source
1384 // of an assignment. This little hack prevents us from
1385 // having to allocate another expression
1388 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1396 EmitCode (ec, true);
1399 protected virtual void EmitOperation (EmitContext ec)
1401 operation.Emit (ec);
1404 public override void EmitStatement (EmitContext ec)
1406 EmitCode (ec, false);
1409 public override void FlowAnalysis (FlowAnalysisContext fc)
1411 expr.FlowAnalysis (fc);
1415 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1417 string GetOperatorExpressionTypeName ()
1419 return IsDecrement ? "Decrement" : "Increment";
1423 get { return (mode & Mode.IsDecrement) != 0; }
1427 public override SLE.Expression MakeExpression (BuilderContext ctx)
1429 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1430 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1431 return SLE.Expression.Assign (target, source);
1434 public static string OperName (Mode oper)
1436 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1439 protected override void CloneTo (CloneContext clonectx, Expression t)
1441 UnaryMutator target = (UnaryMutator) t;
1443 target.expr = expr.Clone (clonectx);
1446 public override object Accept (StructuralVisitor visitor)
1448 return visitor.Visit (this);
1454 // Base class for the `is' and `as' operators
1456 public abstract class Probe : Expression
1458 public Expression ProbeType;
1459 protected Expression expr;
1460 protected TypeSpec probe_type_expr;
1462 protected Probe (Expression expr, Expression probe_type, Location l)
1464 ProbeType = probe_type;
1469 public Expression Expr {
1475 public override bool ContainsEmitWithAwait ()
1477 return expr.ContainsEmitWithAwait ();
1480 protected Expression ResolveCommon (ResolveContext rc)
1482 expr = expr.Resolve (rc);
1486 ResolveProbeType (rc);
1487 if (probe_type_expr == null)
1490 if (probe_type_expr.IsStatic) {
1491 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1492 probe_type_expr.GetSignatureForError ());
1496 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1497 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1502 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1503 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1511 protected virtual void ResolveProbeType (ResolveContext rc)
1513 probe_type_expr = ProbeType.ResolveAsType (rc);
1516 public override void EmitSideEffect (EmitContext ec)
1518 expr.EmitSideEffect (ec);
1521 public override void FlowAnalysis (FlowAnalysisContext fc)
1523 expr.FlowAnalysis (fc);
1526 public override bool HasConditionalAccess ()
1528 return expr.HasConditionalAccess ();
1531 protected abstract string OperatorName { get; }
1533 protected override void CloneTo (CloneContext clonectx, Expression t)
1535 Probe target = (Probe) t;
1537 target.expr = expr.Clone (clonectx);
1538 target.ProbeType = ProbeType.Clone (clonectx);
1544 /// Implementation of the `is' operator.
1546 public class Is : Probe
1548 Nullable.Unwrap expr_unwrap;
1549 MethodSpec number_mg;
1550 Arguments number_args;
1552 public Is (Expression expr, Expression probe_type, Location l)
1553 : base (expr, probe_type, l)
1557 protected override string OperatorName {
1558 get { return "is"; }
1561 public LocalVariable Variable { get; set; }
1563 public override Expression CreateExpressionTree (ResolveContext ec)
1565 if (Variable != null)
1566 throw new NotSupportedException ();
1568 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1569 expr.CreateExpressionTree (ec),
1570 new TypeOf (probe_type_expr, loc));
1572 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1575 Expression CreateConstantResult (ResolveContext rc, bool result)
1578 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1579 probe_type_expr.GetSignatureForError ());
1581 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1582 probe_type_expr.GetSignatureForError ());
1584 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1585 return expr.IsSideEffectFree ?
1586 ReducedExpression.Create (c, this) :
1587 new SideEffectConstant (c, this, loc);
1590 public override void Emit (EmitContext ec)
1592 if (probe_type_expr == null) {
1593 if (ProbeType is WildcardPattern) {
1594 expr.EmitSideEffect (ec);
1595 ProbeType.Emit (ec);
1597 EmitPatternMatch (ec);
1604 if (expr_unwrap == null) {
1606 ec.Emit (OpCodes.Cgt_Un);
1610 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1612 if (probe_type_expr == null) {
1613 EmitPatternMatch (ec);
1618 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1621 void EmitPatternMatch (EmitContext ec)
1623 var no_match = ec.DefineLabel ();
1624 var end = ec.DefineLabel ();
1626 if (expr_unwrap != null) {
1627 expr_unwrap.EmitCheck (ec);
1629 if (ProbeType.IsNull) {
1631 ec.Emit (OpCodes.Ceq);
1635 ec.Emit (OpCodes.Brfalse_S, no_match);
1636 expr_unwrap.Emit (ec);
1637 ProbeType.Emit (ec);
1638 ec.Emit (OpCodes.Ceq);
1639 ec.Emit (OpCodes.Br_S, end);
1640 ec.MarkLabel (no_match);
1646 if (number_args != null && number_args.Count == 3) {
1647 var ce = new CallEmitter ();
1648 ce.Emit (ec, number_mg, number_args, loc);
1652 var probe_type = ProbeType.Type;
1655 ec.Emit (OpCodes.Isinst, probe_type);
1656 ec.Emit (OpCodes.Dup);
1657 ec.Emit (OpCodes.Brfalse, no_match);
1659 bool complex_pattern = ProbeType is ComplexPatternExpression;
1660 Label prev = ec.RecursivePatternLabel;
1661 if (complex_pattern)
1662 ec.RecursivePatternLabel = ec.DefineLabel ();
1664 if (number_mg != null) {
1665 var ce = new CallEmitter ();
1666 ce.Emit (ec, number_mg, number_args, loc);
1668 if (TypeSpec.IsValueType (probe_type))
1669 ec.Emit (OpCodes.Unbox_Any, probe_type);
1671 ProbeType.Emit (ec);
1672 if (complex_pattern) {
1675 ec.Emit (OpCodes.Ceq);
1678 ec.Emit (OpCodes.Br_S, end);
1679 ec.MarkLabel (no_match);
1681 ec.Emit (OpCodes.Pop);
1683 if (complex_pattern)
1684 ec.MarkLabel (ec.RecursivePatternLabel);
1686 ec.RecursivePatternLabel = prev;
1692 void EmitLoad (EmitContext ec)
1694 Label no_value_label = new Label ();
1696 if (expr_unwrap != null) {
1697 expr_unwrap.EmitCheck (ec);
1699 if (Variable == null)
1702 ec.Emit (OpCodes.Dup);
1703 no_value_label = ec.DefineLabel ();
1704 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1705 expr_unwrap.Emit (ec);
1709 // Only to make verifier happy
1710 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1711 ec.Emit (OpCodes.Box, expr.Type);
1713 ec.Emit (OpCodes.Isinst, probe_type_expr);
1716 if (Variable != null) {
1717 bool value_on_stack;
1718 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1719 ec.Emit (OpCodes.Dup);
1720 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1721 value_on_stack = true;
1723 value_on_stack = false;
1726 Variable.CreateBuilder (ec);
1727 Variable.EmitAssign (ec);
1729 if (expr_unwrap != null) {
1730 ec.MarkLabel (no_value_label);
1731 } else if (!value_on_stack) {
1737 protected override Expression DoResolve (ResolveContext rc)
1739 if (ResolveCommon (rc) == null)
1742 type = rc.BuiltinTypes.Bool;
1743 eclass = ExprClass.Value;
1745 if (probe_type_expr == null)
1746 return ResolveMatchingExpression (rc);
1748 var res = ResolveResultExpression (rc);
1749 if (Variable != null) {
1750 if (res is Constant)
1751 throw new NotImplementedException ("constant in type pattern matching");
1753 Variable.Type = probe_type_expr;
1754 var bc = rc as BlockContext;
1756 Variable.PrepareAssignmentAnalysis (bc);
1762 public override void FlowAnalysis (FlowAnalysisContext fc)
1764 base.FlowAnalysis (fc);
1766 if (Variable != null)
1767 fc.SetVariableAssigned (Variable.VariableInfo, true);
1770 protected override void ResolveProbeType (ResolveContext rc)
1772 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1773 if (ProbeType is PatternExpression) {
1774 ProbeType.Resolve (rc);
1779 // Have to use session recording because we don't have reliable type probing
1780 // mechanism (similar issue as in attributes resolving)
1782 // TODO: This is still wrong because ResolveAsType can be destructive
1784 var type_printer = new SessionReportPrinter ();
1785 var prev_recorder = rc.Report.SetPrinter (type_printer);
1787 probe_type_expr = ProbeType.ResolveAsType (rc);
1788 type_printer.EndSession ();
1790 if (probe_type_expr != null) {
1791 type_printer.Merge (rc.Report.Printer);
1792 rc.Report.SetPrinter (prev_recorder);
1796 var vexpr = ProbeType as VarExpr;
1797 if (vexpr != null && vexpr.InferType (rc, expr)) {
1798 probe_type_expr = vexpr.Type;
1799 rc.Report.SetPrinter (prev_recorder);
1803 var expr_printer = new SessionReportPrinter ();
1804 rc.Report.SetPrinter (expr_printer);
1805 ProbeType = ProbeType.Resolve (rc);
1806 expr_printer.EndSession ();
1808 if (ProbeType != null) {
1809 expr_printer.Merge (rc.Report.Printer);
1811 type_printer.Merge (rc.Report.Printer);
1814 rc.Report.SetPrinter (prev_recorder);
1818 base.ResolveProbeType (rc);
1821 Expression ResolveMatchingExpression (ResolveContext rc)
1823 var mc = ProbeType as Constant;
1825 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1826 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1831 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1833 var c = Expr as Constant;
1835 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1840 if (Expr.Type.IsNullableType) {
1841 expr_unwrap = new Nullable.Unwrap (Expr);
1842 expr_unwrap.Resolve (rc);
1843 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1844 } else if (ProbeType.Type == Expr.Type) {
1845 // TODO: Better error handling
1846 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1847 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1848 var helper = rc.Module.CreatePatterMatchingHelper ();
1849 number_mg = helper.NumberMatcher.Spec;
1852 // There are actually 3 arguments but the first one is already on the stack
1854 number_args = new Arguments (3);
1855 if (!ProbeType.Type.IsEnum)
1856 number_args.Add (new Argument (Expr));
1858 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1859 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1865 if (ProbeType is PatternExpression) {
1866 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1867 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1873 // TODO: Better error message
1874 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1878 Expression ResolveResultExpression (ResolveContext ec)
1880 TypeSpec d = expr.Type;
1881 bool d_is_nullable = false;
1884 // If E is a method group or the null literal, or if the type of E is a reference
1885 // type or a nullable type and the value of E is null, the result is false
1887 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1888 return CreateConstantResult (ec, false);
1890 if (d.IsNullableType) {
1891 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1892 if (!ut.IsGenericParameter) {
1894 d_is_nullable = true;
1898 TypeSpec t = probe_type_expr;
1899 bool t_is_nullable = false;
1900 if (t.IsNullableType) {
1901 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1902 if (!ut.IsGenericParameter) {
1904 t_is_nullable = true;
1911 // D and T are the same value types but D can be null
1913 if (d_is_nullable && !t_is_nullable) {
1914 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1919 // The result is true if D and T are the same value types
1921 return CreateConstantResult (ec, true);
1924 var tp = d as TypeParameterSpec;
1926 return ResolveGenericParameter (ec, t, tp);
1929 // An unboxing conversion exists
1931 if (Convert.ExplicitReferenceConversionExists (d, t))
1935 // open generic type
1937 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1940 var tps = t as TypeParameterSpec;
1942 return ResolveGenericParameter (ec, d, tps);
1944 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1945 ec.Report.Warning (1981, 3, loc,
1946 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1947 OperatorName, t.GetSignatureForError ());
1950 if (TypeManager.IsGenericParameter (d))
1951 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1953 if (TypeSpec.IsValueType (d)) {
1954 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1955 if (d_is_nullable && !t_is_nullable) {
1956 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1960 return CreateConstantResult (ec, true);
1963 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1964 var c = expr as Constant;
1966 return CreateConstantResult (ec, !c.IsNull);
1969 // Do not optimize for imported type or dynamic type
1971 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1972 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1976 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1980 // Turn is check into simple null check for implicitly convertible reference types
1982 return ReducedExpression.Create (
1983 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1987 if (Convert.ExplicitReferenceConversionExists (d, t))
1991 // open generic type
1993 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1998 return CreateConstantResult (ec, false);
2001 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
2003 if (t.IsReferenceType) {
2005 return CreateConstantResult (ec, false);
2008 if (expr.Type.IsGenericParameter) {
2009 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2010 return CreateConstantResult (ec, true);
2012 expr = new BoxedCast (expr, d);
2018 public override object Accept (StructuralVisitor visitor)
2020 return visitor.Visit (this);
2024 class WildcardPattern : PatternExpression
2026 public WildcardPattern (Location loc)
2031 protected override Expression DoResolve (ResolveContext rc)
2033 eclass = ExprClass.Value;
2034 type = rc.BuiltinTypes.Object;
2038 public override void Emit (EmitContext ec)
2044 class RecursivePattern : ComplexPatternExpression
2046 MethodGroupExpr operator_mg;
2047 Arguments operator_args;
2049 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2050 : base (typeExpresion, loc)
2052 Arguments = arguments;
2055 public Arguments Arguments { get; private set; }
2057 protected override Expression DoResolve (ResolveContext rc)
2059 type = TypeExpression.ResolveAsType (rc);
2063 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2064 if (operators == null) {
2065 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2069 var ops = FindMatchingOverloads (operators);
2071 // TODO: better error message
2072 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2077 Arguments.Resolve (rc, out dynamic_args);
2079 throw new NotImplementedException ("dynamic argument");
2081 var op = FindBestOverload (rc, ops);
2083 // TODO: better error message
2084 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2088 var op_types = op.Parameters.Types;
2089 operator_args = new Arguments (op_types.Length);
2090 operator_args.Add (new Argument (new EmptyExpression (type)));
2092 for (int i = 0; i < Arguments.Count; ++i) {
2093 // TODO: Needs releasing optimization
2094 var lt = new LocalTemporary (op_types [i + 1]);
2095 operator_args.Add (new Argument (lt, Argument.AType.Out));
2097 if (comparisons == null)
2098 comparisons = new Expression[Arguments.Count];
2103 var arg = Arguments [i];
2104 var named = arg as NamedArgument;
2105 if (named != null) {
2106 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2107 expr = Arguments [arg_comp_index].Expr;
2113 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2116 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2118 eclass = ExprClass.Value;
2122 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2124 int arg_count = Arguments.Count + 1;
2125 List<MethodSpec> best = null;
2126 foreach (MethodSpec method in members) {
2127 var pm = method.Parameters;
2128 if (pm.Count != arg_count)
2131 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2133 for (int ii = 1; ii < pm.Count; ++ii) {
2134 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2144 best = new List<MethodSpec> ();
2152 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2154 for (int ii = 0; ii < Arguments.Count; ++ii) {
2155 var arg = Arguments [ii];
2156 var expr = arg.Expr;
2157 if (expr is WildcardPattern)
2160 var na = arg as NamedArgument;
2161 for (int i = 0; i < methods.Count; ++i) {
2162 var pd = methods [i].Parameters;
2166 index = pd.GetParameterIndexByName (na.Name);
2168 methods.RemoveAt (i--);
2175 var m = pd.Types [index];
2176 if (!Convert.ImplicitConversionExists (rc, expr, m))
2177 methods.RemoveAt (i--);
2181 if (methods.Count != 1)
2187 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2189 operator_mg.EmitCall (ec, operator_args, false);
2190 ec.Emit (OpCodes.Brfalse, target);
2192 base.EmitBranchable (ec, target, on_true);
2195 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2197 if (expr is WildcardPattern)
2198 return new EmptyExpression (expr.Type);
2200 var recursive = expr as RecursivePattern;
2201 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2205 if (recursive != null) {
2206 recursive.SetParentInstance (lt);
2210 // TODO: Better error handling
2211 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2214 public void SetParentInstance (Expression instance)
2216 operator_args [0] = new Argument (instance);
2220 class PropertyPattern : ComplexPatternExpression
2222 LocalTemporary instance;
2224 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2225 : base (typeExpresion, loc)
2230 public List<PropertyPatternMember> Members { get; private set; }
2232 protected override Expression DoResolve (ResolveContext rc)
2234 type = TypeExpression.ResolveAsType (rc);
2238 comparisons = new Expression[Members.Count];
2240 // TODO: optimize when source is VariableReference, it'd save dup+pop
2241 instance = new LocalTemporary (type);
2243 for (int i = 0; i < Members.Count; i++) {
2244 var lookup = Members [i];
2246 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2247 if (member == null) {
2248 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2249 if (member != null) {
2250 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2255 if (member == null) {
2256 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2260 var pe = member as PropertyExpr;
2261 if (pe == null || member is FieldExpr) {
2262 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2266 // TODO: Obsolete checks
2267 // TODO: check accessibility
2268 if (pe != null && !pe.PropertyInfo.HasGet) {
2269 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2273 var expr = lookup.Expr.Resolve (rc);
2277 var me = (MemberExpr)member;
2278 me.InstanceExpression = instance;
2280 comparisons [i] = ResolveComparison (rc, expr, me);
2283 eclass = ExprClass.Value;
2287 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2289 if (expr is WildcardPattern)
2290 return new EmptyExpression (expr.Type);
2292 return new Is (instance, expr, expr.Location).Resolve (rc);
2295 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2297 instance.Store (ec);
2299 base.EmitBranchable (ec, target, on_true);
2303 class PropertyPatternMember
2305 public PropertyPatternMember (string name, Expression expr, Location loc)
2312 public string Name { get; private set; }
2313 public Expression Expr { get; private set; }
2314 public Location Location { get; private set; }
2317 abstract class PatternExpression : Expression
2319 protected PatternExpression (Location loc)
2324 public override Expression CreateExpressionTree (ResolveContext ec)
2326 throw new NotImplementedException ();
2330 abstract class ComplexPatternExpression : PatternExpression
2332 protected Expression[] comparisons;
2334 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2337 TypeExpression = typeExpresion;
2340 public ATypeNameExpression TypeExpression { get; private set; }
2342 public override void Emit (EmitContext ec)
2344 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2347 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2349 if (comparisons != null) {
2350 foreach (var comp in comparisons) {
2351 comp.EmitBranchable (ec, target, false);
2358 /// Implementation of the `as' operator.
2360 public class As : Probe {
2362 public As (Expression expr, Expression probe_type, Location l)
2363 : base (expr, probe_type, l)
2367 protected override string OperatorName {
2368 get { return "as"; }
2371 public override Expression CreateExpressionTree (ResolveContext ec)
2373 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2374 expr.CreateExpressionTree (ec),
2375 new TypeOf (probe_type_expr, loc));
2377 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2380 public override void Emit (EmitContext ec)
2384 ec.Emit (OpCodes.Isinst, type);
2386 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2387 ec.Emit (OpCodes.Unbox_Any, type);
2390 protected override Expression DoResolve (ResolveContext ec)
2392 if (ResolveCommon (ec) == null)
2395 type = probe_type_expr;
2396 eclass = ExprClass.Value;
2397 TypeSpec etype = expr.Type;
2399 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2400 if (TypeManager.IsGenericParameter (type)) {
2401 ec.Report.Error (413, loc,
2402 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2403 probe_type_expr.GetSignatureForError ());
2405 ec.Report.Error (77, loc,
2406 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2407 type.GetSignatureForError ());
2412 if (expr.IsNull && type.IsNullableType) {
2413 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2416 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2417 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2421 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2423 e = EmptyCast.Create (e, type);
2424 return ReducedExpression.Create (e, this).Resolve (ec);
2427 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2428 if (TypeManager.IsGenericParameter (etype))
2429 expr = new BoxedCast (expr, etype);
2434 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2435 expr = new BoxedCast (expr, etype);
2439 if (etype != InternalType.ErrorType) {
2440 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2441 etype.GetSignatureForError (), type.GetSignatureForError ());
2447 public override object Accept (StructuralVisitor visitor)
2449 return visitor.Visit (this);
2454 // This represents a typecast in the source language.
2456 public class Cast : ShimExpression {
2457 Expression target_type;
2459 public Cast (Expression cast_type, Expression expr, Location loc)
2462 this.target_type = cast_type;
2466 public Expression TargetType {
2467 get { return target_type; }
2470 protected override Expression DoResolve (ResolveContext ec)
2472 expr = expr.Resolve (ec);
2476 type = target_type.ResolveAsType (ec);
2480 if (type.IsStatic) {
2481 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2485 if (type.IsPointer && !ec.IsUnsafe) {
2486 UnsafeError (ec, loc);
2489 eclass = ExprClass.Value;
2491 Constant c = expr as Constant;
2493 c = c.Reduce (ec, type);
2498 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2500 return EmptyCast.Create (res, type);
2505 protected override void CloneTo (CloneContext clonectx, Expression t)
2507 Cast target = (Cast) t;
2509 target.target_type = target_type.Clone (clonectx);
2510 target.expr = expr.Clone (clonectx);
2513 public override object Accept (StructuralVisitor visitor)
2515 return visitor.Visit (this);
2519 public class ImplicitCast : ShimExpression
2523 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2526 this.loc = expr.Location;
2528 this.arrayAccess = arrayAccess;
2531 protected override Expression DoResolve (ResolveContext ec)
2533 expr = expr.Resolve (ec);
2538 expr = ConvertExpressionToArrayIndex (ec, expr);
2540 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2546 public class DeclarationExpression : Expression, IMemoryLocation
2548 LocalVariableReference lvr;
2550 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2552 VariableType = variableType;
2553 Variable = variable;
2554 this.loc = variable.Location;
2557 public LocalVariable Variable { get; set; }
2558 public Expression Initializer { get; set; }
2559 public FullNamedExpression VariableType { get; set; }
2561 public void AddressOf (EmitContext ec, AddressOp mode)
2563 Variable.CreateBuilder (ec);
2565 if (Initializer != null) {
2566 lvr.EmitAssign (ec, Initializer, false, false);
2569 lvr.AddressOf (ec, mode);
2572 protected override void CloneTo (CloneContext clonectx, Expression t)
2574 var target = (DeclarationExpression) t;
2576 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2578 if (Initializer != null)
2579 target.Initializer = Initializer.Clone (clonectx);
2582 public override Expression CreateExpressionTree (ResolveContext rc)
2584 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2588 bool DoResolveCommon (ResolveContext rc)
2590 var var_expr = VariableType as VarExpr;
2591 if (var_expr != null) {
2592 type = InternalType.VarOutType;
2594 type = VariableType.ResolveAsType (rc);
2599 if (Initializer != null) {
2600 Initializer = Initializer.Resolve (rc);
2602 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2603 type = var_expr.Type;
2607 Variable.Type = type;
2608 lvr = new LocalVariableReference (Variable, loc);
2610 eclass = ExprClass.Variable;
2614 protected override Expression DoResolve (ResolveContext rc)
2616 if (DoResolveCommon (rc))
2622 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2624 if (lvr == null && DoResolveCommon (rc))
2625 lvr.ResolveLValue (rc, right_side);
2630 public override void Emit (EmitContext ec)
2632 throw new NotImplementedException ();
2637 // C# 2.0 Default value expression
2639 public class DefaultValueExpression : Expression
2643 public DefaultValueExpression (Expression expr, Location loc)
2649 public Expression Expr {
2655 public override bool IsSideEffectFree {
2661 public override bool ContainsEmitWithAwait ()
2666 public override Expression CreateExpressionTree (ResolveContext ec)
2668 Arguments args = new Arguments (2);
2669 args.Add (new Argument (this));
2670 args.Add (new Argument (new TypeOf (type, loc)));
2671 return CreateExpressionFactoryCall (ec, "Constant", args);
2674 protected override Expression DoResolve (ResolveContext ec)
2676 type = expr.ResolveAsType (ec);
2680 if (type.IsStatic) {
2681 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2685 return new NullLiteral (Location).ConvertImplicitly (type);
2687 if (TypeSpec.IsReferenceType (type))
2688 return new NullConstant (type, loc);
2690 Constant c = New.Constantify (type, expr.Location);
2694 eclass = ExprClass.Variable;
2698 public override void Emit (EmitContext ec)
2700 LocalTemporary temp_storage = new LocalTemporary(type);
2702 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2703 ec.Emit(OpCodes.Initobj, type);
2704 temp_storage.Emit(ec);
2705 temp_storage.Release (ec);
2709 public override SLE.Expression MakeExpression (BuilderContext ctx)
2711 return SLE.Expression.Default (type.GetMetaInfo ());
2715 protected override void CloneTo (CloneContext clonectx, Expression t)
2717 DefaultValueExpression target = (DefaultValueExpression) t;
2719 target.expr = expr.Clone (clonectx);
2722 public override object Accept (StructuralVisitor visitor)
2724 return visitor.Visit (this);
2729 /// Binary operators
2731 public class Binary : Expression, IDynamicBinder
2733 public class PredefinedOperator
2735 protected readonly TypeSpec left;
2736 protected readonly TypeSpec right;
2737 protected readonly TypeSpec left_unwrap;
2738 protected readonly TypeSpec right_unwrap;
2739 public readonly Operator OperatorsMask;
2740 public TypeSpec ReturnType;
2742 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2743 : this (ltype, rtype, op_mask, ltype)
2747 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2748 : this (type, type, op_mask, return_type)
2752 public PredefinedOperator (TypeSpec type, Operator op_mask)
2753 : this (type, type, op_mask, type)
2757 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2759 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2760 throw new InternalErrorException ("Only masked values can be used");
2762 if ((op_mask & Operator.NullableMask) != 0) {
2763 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2764 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2766 left_unwrap = ltype;
2767 right_unwrap = rtype;
2772 this.OperatorsMask = op_mask;
2773 this.ReturnType = return_type;
2776 public bool IsLifted {
2778 return (OperatorsMask & Operator.NullableMask) != 0;
2782 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2786 var left_expr = b.left;
2787 var right_expr = b.right;
2789 b.type = ReturnType;
2792 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2793 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2794 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2797 if (right_expr.IsNull) {
2798 if ((b.oper & Operator.EqualityMask) != 0) {
2799 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2800 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2801 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2802 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2803 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2805 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2806 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2808 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2809 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2811 return b.CreateLiftedValueTypeResult (rc, left);
2813 } else if (left_expr.IsNull) {
2814 if ((b.oper & Operator.EqualityMask) != 0) {
2815 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2816 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2817 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2818 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2819 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2821 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2822 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2824 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2825 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2827 return b.CreateLiftedValueTypeResult (rc, right);
2833 // A user operators does not support multiple user conversions, but decimal type
2834 // is considered to be predefined type therefore we apply predefined operators rules
2835 // and then look for decimal user-operator implementation
2837 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2838 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2839 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2841 return b.ResolveUserOperator (rc, b.left, b.right);
2844 c = right_expr as Constant;
2846 if (c.IsDefaultValue) {
2850 // (expr + 0) to expr
2851 // (expr - 0) to expr
2852 // (bool? | false) to bool?
2854 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2855 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2856 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2857 return ReducedExpression.Create (b.left, b).Resolve (rc);
2861 // Optimizes (value &/&& 0) to 0
2863 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2864 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2865 return ReducedExpression.Create (side_effect, b);
2869 // Optimizes (bool? & true) to bool?
2871 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2872 return ReducedExpression.Create (b.left, b).Resolve (rc);
2876 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2877 return ReducedExpression.Create (b.left, b).Resolve (rc);
2879 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2880 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2884 c = b.left as Constant;
2886 if (c.IsDefaultValue) {
2890 // (0 + expr) to expr
2891 // (false | bool?) to bool?
2893 if (b.oper == Operator.Addition ||
2894 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2895 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2896 return ReducedExpression.Create (b.right, b).Resolve (rc);
2900 // Optimizes (false && expr) to false
2902 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2903 // No rhs side-effects
2904 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2905 return ReducedExpression.Create (c, b);
2909 // Optimizes (0 & value) to 0
2911 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2912 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2913 return ReducedExpression.Create (side_effect, b);
2917 // Optimizes (true & bool?) to bool?
2919 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2920 return ReducedExpression.Create (b.right, b).Resolve (rc);
2924 // Optimizes (true || expr) to true
2926 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2927 // No rhs side-effects
2928 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2929 return ReducedExpression.Create (c, b);
2933 if (b.oper == Operator.Multiply && c.IsOneInteger)
2934 return ReducedExpression.Create (b.right, b).Resolve (rc);
2938 var lifted = new Nullable.LiftedBinaryOperator (b);
2940 TypeSpec ltype, rtype;
2941 if (b.left.Type.IsNullableType) {
2942 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2943 ltype = left_unwrap;
2948 if (b.right.Type.IsNullableType) {
2949 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2950 rtype = right_unwrap;
2955 lifted.Left = b.left.IsNull ?
2957 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2959 lifted.Right = b.right.IsNull ?
2961 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2963 return lifted.Resolve (rc);
2966 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2967 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2972 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2975 // We are dealing with primitive types only
2977 return left == ltype && ltype == rtype;
2980 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2983 if (left == lexpr.Type && right == rexpr.Type)
2986 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2987 Convert.ImplicitConversionExists (ec, rexpr, right);
2990 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2992 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2993 return best_operator;
2995 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2999 if (left != null && best_operator.left != null) {
3000 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3004 // When second argument is same as the first one, the result is same
3006 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3007 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3010 if (result == 0 || result > 2)
3013 return result == 1 ? best_operator : this;
3017 sealed class PredefinedStringOperator : PredefinedOperator
3019 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3020 : base (type, type, op_mask, retType)
3024 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3025 : base (ltype, rtype, op_mask, retType)
3029 public override Expression ConvertResult (ResolveContext ec, Binary b)
3032 // Use original expression for nullable arguments
3034 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3036 b.left = unwrap.Original;
3038 unwrap = b.right as Nullable.Unwrap;
3040 b.right = unwrap.Original;
3042 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3043 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3046 // Start a new concat expression using converted expression
3048 return StringConcat.Create (ec, b.left, b.right, b.loc);
3052 sealed class PredefinedEqualityOperator : PredefinedOperator
3054 MethodSpec equal_method, inequal_method;
3056 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3057 : base (arg, arg, Operator.EqualityMask, retType)
3061 public override Expression ConvertResult (ResolveContext ec, Binary b)
3063 b.type = ReturnType;
3065 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3066 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3068 Arguments args = new Arguments (2);
3069 args.Add (new Argument (b.left));
3070 args.Add (new Argument (b.right));
3073 if (b.oper == Operator.Equality) {
3074 if (equal_method == null) {
3075 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3076 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3077 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3078 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3080 throw new NotImplementedException (left.GetSignatureForError ());
3083 method = equal_method;
3085 if (inequal_method == null) {
3086 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3087 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3088 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3089 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3091 throw new NotImplementedException (left.GetSignatureForError ());
3094 method = inequal_method;
3097 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3101 class PredefinedPointerOperator : PredefinedOperator
3103 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3104 : base (ltype, rtype, op_mask)
3108 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3109 : base (ltype, rtype, op_mask, retType)
3113 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3114 : base (type, op_mask, return_type)
3118 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3121 if (!lexpr.Type.IsPointer)
3124 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3128 if (right == null) {
3129 if (!rexpr.Type.IsPointer)
3132 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3139 public override Expression ConvertResult (ResolveContext ec, Binary b)
3142 b.left = EmptyCast.Create (b.left, left);
3143 } else if (right != null) {
3144 b.right = EmptyCast.Create (b.right, right);
3147 TypeSpec r_type = ReturnType;
3148 Expression left_arg, right_arg;
3149 if (r_type == null) {
3152 right_arg = b.right;
3153 r_type = b.left.Type;
3157 r_type = b.right.Type;
3161 right_arg = b.right;
3164 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3169 public enum Operator {
3170 Multiply = 0 | ArithmeticMask,
3171 Division = 1 | ArithmeticMask,
3172 Modulus = 2 | ArithmeticMask,
3173 Addition = 3 | ArithmeticMask | AdditionMask,
3174 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3176 LeftShift = 5 | ShiftMask,
3177 RightShift = 6 | ShiftMask,
3179 LessThan = 7 | ComparisonMask | RelationalMask,
3180 GreaterThan = 8 | ComparisonMask | RelationalMask,
3181 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3182 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3183 Equality = 11 | ComparisonMask | EqualityMask,
3184 Inequality = 12 | ComparisonMask | EqualityMask,
3186 BitwiseAnd = 13 | BitwiseMask,
3187 ExclusiveOr = 14 | BitwiseMask,
3188 BitwiseOr = 15 | BitwiseMask,
3190 LogicalAnd = 16 | LogicalMask,
3191 LogicalOr = 17 | LogicalMask,
3196 ValuesOnlyMask = ArithmeticMask - 1,
3197 ArithmeticMask = 1 << 5,
3199 ComparisonMask = 1 << 7,
3200 EqualityMask = 1 << 8,
3201 BitwiseMask = 1 << 9,
3202 LogicalMask = 1 << 10,
3203 AdditionMask = 1 << 11,
3204 SubtractionMask = 1 << 12,
3205 RelationalMask = 1 << 13,
3207 DecomposedMask = 1 << 19,
3208 NullableMask = 1 << 20
3212 public enum State : byte
3216 UserOperatorsExcluded = 1 << 2
3219 readonly Operator oper;
3220 Expression left, right;
3222 ConvCast.Mode enum_conversion;
3224 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3225 : this (oper, left, right, State.Compound)
3229 public Binary (Operator oper, Expression left, Expression right, State state)
3230 : this (oper, left, right)
3235 public Binary (Operator oper, Expression left, Expression right)
3236 : this (oper, left, right, left.Location)
3240 public Binary (Operator oper, Expression left, Expression right, Location loc)
3250 public bool IsCompound {
3252 return (state & State.Compound) != 0;
3256 public Operator Oper {
3262 public Expression Left {
3268 public Expression Right {
3274 public override Location StartLocation {
3276 return left.StartLocation;
3283 /// Returns a stringified representation of the Operator
3285 string OperName (Operator oper)
3289 case Operator.Multiply:
3292 case Operator.Division:
3295 case Operator.Modulus:
3298 case Operator.Addition:
3301 case Operator.Subtraction:
3304 case Operator.LeftShift:
3307 case Operator.RightShift:
3310 case Operator.LessThan:
3313 case Operator.GreaterThan:
3316 case Operator.LessThanOrEqual:
3319 case Operator.GreaterThanOrEqual:
3322 case Operator.Equality:
3325 case Operator.Inequality:
3328 case Operator.BitwiseAnd:
3331 case Operator.BitwiseOr:
3334 case Operator.ExclusiveOr:
3337 case Operator.LogicalOr:
3340 case Operator.LogicalAnd:
3344 s = oper.ToString ();
3354 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3356 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3359 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3361 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3365 l = left.Type.GetSignatureForError ();
3366 r = right.Type.GetSignatureForError ();
3368 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3372 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3374 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3377 public override void FlowAnalysis (FlowAnalysisContext fc)
3380 // Optimized version when on-true/on-false data are not needed
3382 if ((oper & Operator.LogicalMask) == 0) {
3383 left.FlowAnalysis (fc);
3384 right.FlowAnalysis (fc);
3388 left.FlowAnalysisConditional (fc);
3389 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3390 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3392 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3393 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3394 right.FlowAnalysisConditional (fc);
3396 if (oper == Operator.LogicalOr)
3397 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3399 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3402 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3404 if ((oper & Operator.LogicalMask) == 0) {
3405 base.FlowAnalysisConditional (fc);
3409 left.FlowAnalysisConditional (fc);
3410 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3411 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3413 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3414 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3415 right.FlowAnalysisConditional (fc);
3417 var lc = left as Constant;
3418 if (oper == Operator.LogicalOr) {
3419 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3420 if (lc != null && lc.IsDefaultValue)
3421 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3423 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3425 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3426 if (lc != null && !lc.IsDefaultValue)
3427 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3429 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3434 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3436 string GetOperatorExpressionTypeName ()
3439 case Operator.Addition:
3440 return IsCompound ? "AddAssign" : "Add";
3441 case Operator.BitwiseAnd:
3442 return IsCompound ? "AndAssign" : "And";
3443 case Operator.BitwiseOr:
3444 return IsCompound ? "OrAssign" : "Or";
3445 case Operator.Division:
3446 return IsCompound ? "DivideAssign" : "Divide";
3447 case Operator.ExclusiveOr:
3448 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3449 case Operator.Equality:
3451 case Operator.GreaterThan:
3452 return "GreaterThan";
3453 case Operator.GreaterThanOrEqual:
3454 return "GreaterThanOrEqual";
3455 case Operator.Inequality:
3457 case Operator.LeftShift:
3458 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3459 case Operator.LessThan:
3461 case Operator.LessThanOrEqual:
3462 return "LessThanOrEqual";
3463 case Operator.LogicalAnd:
3465 case Operator.LogicalOr:
3467 case Operator.Modulus:
3468 return IsCompound ? "ModuloAssign" : "Modulo";
3469 case Operator.Multiply:
3470 return IsCompound ? "MultiplyAssign" : "Multiply";
3471 case Operator.RightShift:
3472 return IsCompound ? "RightShiftAssign" : "RightShift";
3473 case Operator.Subtraction:
3474 return IsCompound ? "SubtractAssign" : "Subtract";
3476 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3480 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3483 case Operator.Addition:
3484 return CSharp.Operator.OpType.Addition;
3485 case Operator.BitwiseAnd:
3486 case Operator.LogicalAnd:
3487 return CSharp.Operator.OpType.BitwiseAnd;
3488 case Operator.BitwiseOr:
3489 case Operator.LogicalOr:
3490 return CSharp.Operator.OpType.BitwiseOr;
3491 case Operator.Division:
3492 return CSharp.Operator.OpType.Division;
3493 case Operator.Equality:
3494 return CSharp.Operator.OpType.Equality;
3495 case Operator.ExclusiveOr:
3496 return CSharp.Operator.OpType.ExclusiveOr;
3497 case Operator.GreaterThan:
3498 return CSharp.Operator.OpType.GreaterThan;
3499 case Operator.GreaterThanOrEqual:
3500 return CSharp.Operator.OpType.GreaterThanOrEqual;
3501 case Operator.Inequality:
3502 return CSharp.Operator.OpType.Inequality;
3503 case Operator.LeftShift:
3504 return CSharp.Operator.OpType.LeftShift;
3505 case Operator.LessThan:
3506 return CSharp.Operator.OpType.LessThan;
3507 case Operator.LessThanOrEqual:
3508 return CSharp.Operator.OpType.LessThanOrEqual;
3509 case Operator.Modulus:
3510 return CSharp.Operator.OpType.Modulus;
3511 case Operator.Multiply:
3512 return CSharp.Operator.OpType.Multiply;
3513 case Operator.RightShift:
3514 return CSharp.Operator.OpType.RightShift;
3515 case Operator.Subtraction:
3516 return CSharp.Operator.OpType.Subtraction;
3518 throw new InternalErrorException (op.ToString ());
3522 public override bool ContainsEmitWithAwait ()
3524 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3527 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3532 case Operator.Multiply:
3533 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3534 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3535 opcode = OpCodes.Mul_Ovf;
3536 else if (!IsFloat (l))
3537 opcode = OpCodes.Mul_Ovf_Un;
3539 opcode = OpCodes.Mul;
3541 opcode = OpCodes.Mul;
3545 case Operator.Division:
3547 opcode = OpCodes.Div_Un;
3549 opcode = OpCodes.Div;
3552 case Operator.Modulus:
3554 opcode = OpCodes.Rem_Un;
3556 opcode = OpCodes.Rem;
3559 case Operator.Addition:
3560 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3561 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3562 opcode = OpCodes.Add_Ovf;
3563 else if (!IsFloat (l))
3564 opcode = OpCodes.Add_Ovf_Un;
3566 opcode = OpCodes.Add;
3568 opcode = OpCodes.Add;
3571 case Operator.Subtraction:
3572 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3573 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3574 opcode = OpCodes.Sub_Ovf;
3575 else if (!IsFloat (l))
3576 opcode = OpCodes.Sub_Ovf_Un;
3578 opcode = OpCodes.Sub;
3580 opcode = OpCodes.Sub;
3583 case Operator.RightShift:
3584 if (!(right is IntConstant)) {
3585 ec.EmitInt (GetShiftMask (l));
3586 ec.Emit (OpCodes.And);
3590 opcode = OpCodes.Shr_Un;
3592 opcode = OpCodes.Shr;
3595 case Operator.LeftShift:
3596 if (!(right is IntConstant)) {
3597 ec.EmitInt (GetShiftMask (l));
3598 ec.Emit (OpCodes.And);
3601 opcode = OpCodes.Shl;
3604 case Operator.Equality:
3605 opcode = OpCodes.Ceq;
3608 case Operator.Inequality:
3609 ec.Emit (OpCodes.Ceq);
3612 opcode = OpCodes.Ceq;
3615 case Operator.LessThan:
3617 opcode = OpCodes.Clt_Un;
3619 opcode = OpCodes.Clt;
3622 case Operator.GreaterThan:
3624 opcode = OpCodes.Cgt_Un;
3626 opcode = OpCodes.Cgt;
3629 case Operator.LessThanOrEqual:
3630 if (IsUnsigned (l) || IsFloat (l))
3631 ec.Emit (OpCodes.Cgt_Un);
3633 ec.Emit (OpCodes.Cgt);
3636 opcode = OpCodes.Ceq;
3639 case Operator.GreaterThanOrEqual:
3640 if (IsUnsigned (l) || IsFloat (l))
3641 ec.Emit (OpCodes.Clt_Un);
3643 ec.Emit (OpCodes.Clt);
3647 opcode = OpCodes.Ceq;
3650 case Operator.BitwiseOr:
3651 opcode = OpCodes.Or;
3654 case Operator.BitwiseAnd:
3655 opcode = OpCodes.And;
3658 case Operator.ExclusiveOr:
3659 opcode = OpCodes.Xor;
3663 throw new InternalErrorException (oper.ToString ());
3669 static int GetShiftMask (TypeSpec type)
3671 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3674 static bool IsUnsigned (TypeSpec t)
3676 switch (t.BuiltinType) {
3677 case BuiltinTypeSpec.Type.Char:
3678 case BuiltinTypeSpec.Type.UInt:
3679 case BuiltinTypeSpec.Type.ULong:
3680 case BuiltinTypeSpec.Type.UShort:
3681 case BuiltinTypeSpec.Type.Byte:
3688 static bool IsFloat (TypeSpec t)
3690 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3693 public Expression ResolveOperator (ResolveContext rc)
3695 eclass = ExprClass.Value;
3697 TypeSpec l = left.Type;
3698 TypeSpec r = right.Type;
3700 bool primitives_only = false;
3703 // Handles predefined primitive types
3705 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3706 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3707 if ((oper & Operator.ShiftMask) == 0) {
3708 if (!DoBinaryOperatorPromotion (rc))
3711 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3715 if (l.IsPointer || r.IsPointer)
3716 return ResolveOperatorPointer (rc, l, r);
3719 if ((state & State.UserOperatorsExcluded) == 0) {
3720 expr = ResolveUserOperator (rc, left, right);
3725 bool lenum = l.IsEnum;
3726 bool renum = r.IsEnum;
3727 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3731 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3732 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3737 if ((oper & Operator.BitwiseMask) != 0) {
3738 expr = EmptyCast.Create (expr, type);
3739 enum_conversion = GetEnumResultCast (type);
3741 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3742 expr = OptimizeAndOperation (expr);
3746 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3747 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3750 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3751 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3755 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3758 // We cannot break here there is also Enum + String possible match
3759 // which is not ambiguous with predefined enum operators
3762 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3763 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3767 } else if (l.IsDelegate || r.IsDelegate) {
3771 expr = ResolveOperatorDelegate (rc, l, r);
3773 // TODO: Can this be ambiguous
3781 // Equality operators are more complicated
3783 if ((oper & Operator.EqualityMask) != 0) {
3784 return ResolveEquality (rc, l, r, primitives_only);
3787 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3791 if (primitives_only)
3795 // Lifted operators have lower priority
3797 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3800 static bool IsEnumOrNullableEnum (TypeSpec type)
3802 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3806 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3807 // if 'left' is not an enumeration constant, create one from the type of 'right'
3808 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3811 case Operator.BitwiseOr:
3812 case Operator.BitwiseAnd:
3813 case Operator.ExclusiveOr:
3814 case Operator.Equality:
3815 case Operator.Inequality:
3816 case Operator.LessThan:
3817 case Operator.LessThanOrEqual:
3818 case Operator.GreaterThan:
3819 case Operator.GreaterThanOrEqual:
3820 if (left.Type.IsEnum)
3823 if (left.IsZeroInteger)
3824 return left.Reduce (ec, right.Type);
3828 case Operator.Addition:
3829 case Operator.Subtraction:
3832 case Operator.Multiply:
3833 case Operator.Division:
3834 case Operator.Modulus:
3835 case Operator.LeftShift:
3836 case Operator.RightShift:
3837 if (right.Type.IsEnum || left.Type.IsEnum)
3846 // The `|' operator used on types which were extended is dangerous
3848 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3850 OpcodeCast lcast = left as OpcodeCast;
3851 if (lcast != null) {
3852 if (IsUnsigned (lcast.UnderlyingType))
3856 OpcodeCast rcast = right as OpcodeCast;
3857 if (rcast != null) {
3858 if (IsUnsigned (rcast.UnderlyingType))
3862 if (lcast == null && rcast == null)
3865 // FIXME: consider constants
3867 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3868 ec.Report.Warning (675, 3, loc,
3869 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3870 ltype.GetSignatureForError ());
3873 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3875 return new PredefinedOperator[] {
3877 // Pointer arithmetic:
3879 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3880 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3881 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3882 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3884 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3885 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3886 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3887 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3890 // T* operator + (int y, T* x);
3891 // T* operator + (uint y, T *x);
3892 // T* operator + (long y, T *x);
3893 // T* operator + (ulong y, T *x);
3895 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3896 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3897 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3898 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3901 // long operator - (T* x, T *y)
3903 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3907 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3909 TypeSpec bool_type = types.Bool;
3912 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3913 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3914 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3915 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3916 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3917 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3918 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3920 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3921 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3922 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3923 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3924 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3925 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3926 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3928 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3929 // Remaining string operators are in lifted tables
3931 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3933 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3934 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3935 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3939 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3941 var types = module.Compiler.BuiltinTypes;
3944 // Not strictly lifted but need to be in second group otherwise expressions like
3945 // int + null would resolve to +(object, string) instead of +(int?, int?)
3947 var string_operators = new [] {
3948 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3949 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3952 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3953 if (nullable == null)
3954 return string_operators;
3956 var bool_type = types.Bool;
3958 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3959 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3960 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3961 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3962 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3963 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3964 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3965 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3968 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3969 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3970 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3971 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3972 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3973 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3974 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3976 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3977 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3978 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3979 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3980 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3981 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3982 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3984 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3986 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3987 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3988 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3990 string_operators [0],
3991 string_operators [1]
3995 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3997 TypeSpec bool_type = types.Bool;
4000 new PredefinedEqualityOperator (types.String, bool_type),
4001 new PredefinedEqualityOperator (types.Delegate, bool_type),
4002 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4003 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4005 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4006 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4007 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4008 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4009 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4013 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4015 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4017 if (nullable == null)
4018 return new PredefinedOperator [0];
4020 var types = module.Compiler.BuiltinTypes;
4021 var bool_type = types.Bool;
4022 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4023 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4024 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4025 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4026 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4027 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4028 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4029 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4032 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4033 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4034 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4035 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4036 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4037 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4038 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4039 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4044 // 7.2.6.2 Binary numeric promotions
4046 bool DoBinaryOperatorPromotion (ResolveContext rc)
4048 TypeSpec ltype = left.Type;
4049 if (ltype.IsNullableType) {
4050 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4054 // This is numeric promotion code only
4056 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4059 TypeSpec rtype = right.Type;
4060 if (rtype.IsNullableType) {
4061 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4064 var lb = ltype.BuiltinType;
4065 var rb = rtype.BuiltinType;
4069 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4070 type = rc.BuiltinTypes.Decimal;
4071 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4072 type = rc.BuiltinTypes.Double;
4073 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4074 type = rc.BuiltinTypes.Float;
4075 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4076 type = rc.BuiltinTypes.ULong;
4078 if (IsSignedType (lb)) {
4079 expr = ConvertSignedConstant (left, type);
4083 } else if (IsSignedType (rb)) {
4084 expr = ConvertSignedConstant (right, type);
4090 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4091 type = rc.BuiltinTypes.Long;
4092 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4093 type = rc.BuiltinTypes.UInt;
4095 if (IsSignedType (lb)) {
4096 expr = ConvertSignedConstant (left, type);
4098 type = rc.BuiltinTypes.Long;
4099 } else if (IsSignedType (rb)) {
4100 expr = ConvertSignedConstant (right, type);
4102 type = rc.BuiltinTypes.Long;
4105 type = rc.BuiltinTypes.Int;
4108 if (ltype != type) {
4109 expr = PromoteExpression (rc, left, type);
4116 if (rtype != type) {
4117 expr = PromoteExpression (rc, right, type);
4127 static bool IsSignedType (BuiltinTypeSpec.Type type)
4130 case BuiltinTypeSpec.Type.Int:
4131 case BuiltinTypeSpec.Type.Short:
4132 case BuiltinTypeSpec.Type.SByte:
4133 case BuiltinTypeSpec.Type.Long:
4140 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4142 var c = expr as Constant;
4146 return c.ConvertImplicitly (type);
4149 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4151 if (expr.Type.IsNullableType) {
4152 return Convert.ImplicitConversionStandard (rc, expr,
4153 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4156 var c = expr as Constant;
4158 return c.ConvertImplicitly (type);
4160 return Convert.ImplicitNumericConversion (expr, type);
4163 protected override Expression DoResolve (ResolveContext ec)
4168 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4169 left = ((ParenthesizedExpression) left).Expr;
4170 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4174 if (left.eclass == ExprClass.Type) {
4175 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4179 left = left.Resolve (ec);
4184 right = right.Resolve (ec);
4188 Constant lc = left as Constant;
4189 Constant rc = right as Constant;
4191 // The conversion rules are ignored in enum context but why
4192 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4193 lc = EnumLiftUp (ec, lc, rc);
4195 rc = EnumLiftUp (ec, rc, lc);
4198 if (rc != null && lc != null) {
4199 int prev_e = ec.Report.Errors;
4200 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4201 if (e != null || ec.Report.Errors != prev_e)
4205 // Comparison warnings
4206 if ((oper & Operator.ComparisonMask) != 0) {
4207 if (left.Equals (right)) {
4208 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4210 CheckOutOfRangeComparison (ec, lc, right.Type);
4211 CheckOutOfRangeComparison (ec, rc, left.Type);
4214 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4215 return DoResolveDynamic (ec);
4217 return DoResolveCore (ec, left, right);
4220 Expression DoResolveDynamic (ResolveContext rc)
4223 var rt = right.Type;
4224 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4225 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4226 Error_OperatorCannotBeApplied (rc, left, right);
4233 // Special handling for logical boolean operators which require rhs not to be
4234 // evaluated based on lhs value
4236 if ((oper & Operator.LogicalMask) != 0) {
4237 Expression cond_left, cond_right, expr;
4239 args = new Arguments (2);
4241 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4242 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4244 var cond_args = new Arguments (1);
4245 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4248 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4249 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4251 left = temp.CreateReferenceExpression (rc, loc);
4252 if (oper == Operator.LogicalAnd) {
4253 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4256 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4260 args.Add (new Argument (left));
4261 args.Add (new Argument (right));
4262 cond_right = new DynamicExpressionStatement (this, args, loc);
4264 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4266 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4267 rc.Report.Error (7083, left.Location,
4268 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4269 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4273 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4274 args.Add (new Argument (right));
4275 right = new DynamicExpressionStatement (this, args, loc);
4278 // bool && dynamic => (temp = left) ? temp && right : temp;
4279 // bool || dynamic => (temp = left) ? temp : temp || right;
4281 if (oper == Operator.LogicalAnd) {
4283 cond_right = temp.CreateReferenceExpression (rc, loc);
4285 cond_left = temp.CreateReferenceExpression (rc, loc);
4289 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4292 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4295 args = new Arguments (2);
4296 args.Add (new Argument (left));
4297 args.Add (new Argument (right));
4298 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4301 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4303 Expression expr = ResolveOperator (ec);
4305 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4307 if (left == null || right == null)
4308 throw new InternalErrorException ("Invalid conversion");
4310 if (oper == Operator.BitwiseOr)
4311 CheckBitwiseOrOnSignExtended (ec);
4316 public override SLE.Expression MakeExpression (BuilderContext ctx)
4318 return MakeExpression (ctx, left, right);
4321 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4323 var le = left.MakeExpression (ctx);
4324 var re = right.MakeExpression (ctx);
4325 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4328 case Operator.Addition:
4329 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4330 case Operator.BitwiseAnd:
4331 return SLE.Expression.And (le, re);
4332 case Operator.BitwiseOr:
4333 return SLE.Expression.Or (le, re);
4334 case Operator.Division:
4335 return SLE.Expression.Divide (le, re);
4336 case Operator.Equality:
4337 return SLE.Expression.Equal (le, re);
4338 case Operator.ExclusiveOr:
4339 return SLE.Expression.ExclusiveOr (le, re);
4340 case Operator.GreaterThan:
4341 return SLE.Expression.GreaterThan (le, re);
4342 case Operator.GreaterThanOrEqual:
4343 return SLE.Expression.GreaterThanOrEqual (le, re);
4344 case Operator.Inequality:
4345 return SLE.Expression.NotEqual (le, re);
4346 case Operator.LeftShift:
4347 return SLE.Expression.LeftShift (le, re);
4348 case Operator.LessThan:
4349 return SLE.Expression.LessThan (le, re);
4350 case Operator.LessThanOrEqual:
4351 return SLE.Expression.LessThanOrEqual (le, re);
4352 case Operator.LogicalAnd:
4353 return SLE.Expression.AndAlso (le, re);
4354 case Operator.LogicalOr:
4355 return SLE.Expression.OrElse (le, re);
4356 case Operator.Modulus:
4357 return SLE.Expression.Modulo (le, re);
4358 case Operator.Multiply:
4359 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4360 case Operator.RightShift:
4361 return SLE.Expression.RightShift (le, re);
4362 case Operator.Subtraction:
4363 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4365 throw new NotImplementedException (oper.ToString ());
4370 // D operator + (D x, D y)
4371 // D operator - (D x, D y)
4373 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4375 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4377 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4378 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4383 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4384 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4394 MethodSpec method = null;
4395 Arguments args = new Arguments (2);
4396 args.Add (new Argument (left));
4397 args.Add (new Argument (right));
4399 if (oper == Operator.Addition) {
4400 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4401 } else if (oper == Operator.Subtraction) {
4402 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4406 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4408 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4409 return new ClassCast (expr, l);
4413 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4415 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4418 // bool operator == (E x, E y);
4419 // bool operator != (E x, E y);
4420 // bool operator < (E x, E y);
4421 // bool operator > (E x, E y);
4422 // bool operator <= (E x, E y);
4423 // bool operator >= (E x, E y);
4425 // E operator & (E x, E y);
4426 // E operator | (E x, E y);
4427 // E operator ^ (E x, E y);
4430 if ((oper & Operator.ComparisonMask) != 0) {
4431 type = rc.BuiltinTypes.Bool;
4437 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4443 if (ltype == rtype) {
4447 var lifted = new Nullable.LiftedBinaryOperator (this);
4449 lifted.Right = right;
4450 return lifted.Resolve (rc);
4453 if (renum && !ltype.IsNullableType) {
4454 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4459 } else if (lenum && !rtype.IsNullableType) {
4460 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4468 // Now try lifted version of predefined operator
4470 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4471 if (nullable_type != null) {
4472 if (renum && !ltype.IsNullableType) {
4473 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4475 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4478 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4481 if ((oper & Operator.BitwiseMask) != 0)
4485 if ((oper & Operator.BitwiseMask) != 0)
4486 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4488 return CreateLiftedValueTypeResult (rc, rtype);
4492 var lifted = new Nullable.LiftedBinaryOperator (this);
4494 lifted.Right = right;
4495 return lifted.Resolve (rc);
4497 } else if (lenum && !rtype.IsNullableType) {
4498 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4500 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4503 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4506 if ((oper & Operator.BitwiseMask) != 0)
4510 if ((oper & Operator.BitwiseMask) != 0)
4511 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4513 return CreateLiftedValueTypeResult (rc, ltype);
4517 var lifted = new Nullable.LiftedBinaryOperator (this);
4519 lifted.Right = expr;
4520 return lifted.Resolve (rc);
4522 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4523 Nullable.Unwrap unwrap = null;
4524 if (left.IsNull || right.IsNull) {
4525 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4526 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4528 if ((oper & Operator.RelationalMask) != 0)
4529 return CreateLiftedValueTypeResult (rc, rtype);
4531 if ((oper & Operator.BitwiseMask) != 0)
4532 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4535 return CreateLiftedValueTypeResult (rc, left.Type);
4537 // Equality operators are valid between E? and null
4539 unwrap = new Nullable.Unwrap (right);
4541 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4545 if ((oper & Operator.BitwiseMask) != 0)
4550 var lifted = new Nullable.LiftedBinaryOperator (this);
4552 lifted.Right = right;
4553 lifted.UnwrapRight = unwrap;
4554 return lifted.Resolve (rc);
4556 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4557 Nullable.Unwrap unwrap = null;
4558 if (right.IsNull || left.IsNull) {
4559 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4560 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4562 if ((oper & Operator.RelationalMask) != 0)
4563 return CreateLiftedValueTypeResult (rc, ltype);
4565 if ((oper & Operator.BitwiseMask) != 0)
4566 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4569 return CreateLiftedValueTypeResult (rc, right.Type);
4571 // Equality operators are valid between E? and null
4573 unwrap = new Nullable.Unwrap (left);
4575 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4579 if ((oper & Operator.BitwiseMask) != 0)
4584 var lifted = new Nullable.LiftedBinaryOperator (this);
4586 lifted.UnwrapLeft = unwrap;
4587 lifted.Right = expr;
4588 return lifted.Resolve (rc);
4596 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4598 TypeSpec underlying_type;
4599 if (expr.Type.IsNullableType) {
4600 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4602 underlying_type = EnumSpec.GetUnderlyingType (nt);
4604 underlying_type = nt;
4605 } else if (expr.Type.IsEnum) {
4606 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4608 underlying_type = expr.Type;
4611 switch (underlying_type.BuiltinType) {
4612 case BuiltinTypeSpec.Type.SByte:
4613 case BuiltinTypeSpec.Type.Byte:
4614 case BuiltinTypeSpec.Type.Short:
4615 case BuiltinTypeSpec.Type.UShort:
4616 underlying_type = rc.BuiltinTypes.Int;
4620 if (expr.Type.IsNullableType || liftType)
4621 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4623 if (expr.Type == underlying_type)
4626 return EmptyCast.Create (expr, underlying_type);
4629 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4632 // U operator - (E e, E f)
4633 // E operator - (E e, U x) // Internal decomposition operator
4634 // E operator - (U x, E e) // Internal decomposition operator
4636 // E operator + (E e, U x)
4637 // E operator + (U x, E e)
4646 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4652 if (!enum_type.IsNullableType) {
4653 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4655 if (oper == Operator.Subtraction)
4656 expr = ConvertEnumSubtractionResult (rc, expr);
4658 expr = ConvertEnumAdditionalResult (expr, enum_type);
4660 enum_conversion = GetEnumResultCast (expr.Type);
4665 var nullable = rc.Module.PredefinedTypes.Nullable;
4668 // Don't try nullable version when nullable type is undefined
4670 if (!nullable.IsDefined)
4673 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4676 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4678 if (oper == Operator.Subtraction)
4679 expr = ConvertEnumSubtractionResult (rc, expr);
4681 expr = ConvertEnumAdditionalResult (expr, enum_type);
4683 enum_conversion = GetEnumResultCast (expr.Type);
4689 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4691 return EmptyCast.Create (expr, enumType);
4694 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4697 // Enumeration subtraction has different result type based on
4700 TypeSpec result_type;
4701 if (left.Type == right.Type) {
4702 var c = right as EnumConstant;
4703 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4705 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4706 // E which is not what expressions E - 1 or 0 - E return
4708 result_type = left.Type;
4710 result_type = left.Type.IsNullableType ?
4711 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4712 EnumSpec.GetUnderlyingType (left.Type);
4715 if (IsEnumOrNullableEnum (left.Type)) {
4716 result_type = left.Type;
4718 result_type = right.Type;
4721 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4722 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4725 return EmptyCast.Create (expr, result_type);
4728 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4730 if (type.IsNullableType)
4731 type = Nullable.NullableInfo.GetUnderlyingType (type);
4734 type = EnumSpec.GetUnderlyingType (type);
4736 switch (type.BuiltinType) {
4737 case BuiltinTypeSpec.Type.SByte:
4738 return ConvCast.Mode.I4_I1;
4739 case BuiltinTypeSpec.Type.Byte:
4740 return ConvCast.Mode.I4_U1;
4741 case BuiltinTypeSpec.Type.Short:
4742 return ConvCast.Mode.I4_I2;
4743 case BuiltinTypeSpec.Type.UShort:
4744 return ConvCast.Mode.I4_U2;
4751 // Equality operators rules
4753 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4756 type = ec.BuiltinTypes.Bool;
4757 bool no_arg_conv = false;
4759 if (!primitives_only) {
4762 // a, Both operands are reference-type values or the value null
4763 // b, One operand is a value of type T where T is a type-parameter and
4764 // the other operand is the value null. Furthermore T does not have the
4765 // value type constraint
4767 // LAMESPEC: Very confusing details in the specification, basically any
4768 // reference like type-parameter is allowed
4770 var tparam_l = l as TypeParameterSpec;
4771 var tparam_r = r as TypeParameterSpec;
4772 if (tparam_l != null) {
4773 if (right is NullLiteral) {
4774 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4777 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4781 if (!tparam_l.IsReferenceType)
4784 l = tparam_l.GetEffectiveBase ();
4785 left = new BoxedCast (left, l);
4786 } else if (left is NullLiteral && tparam_r == null) {
4787 if (TypeSpec.IsReferenceType (r))
4790 if (r.Kind == MemberKind.InternalCompilerType)
4794 if (tparam_r != null) {
4795 if (left is NullLiteral) {
4796 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4799 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4803 if (!tparam_r.IsReferenceType)
4806 r = tparam_r.GetEffectiveBase ();
4807 right = new BoxedCast (right, r);
4808 } else if (right is NullLiteral) {
4809 if (TypeSpec.IsReferenceType (l))
4812 if (l.Kind == MemberKind.InternalCompilerType)
4817 // LAMESPEC: method groups can be compared when they convert to other side delegate
4820 if (right.eclass == ExprClass.MethodGroup) {
4821 result = Convert.ImplicitConversion (ec, right, l, loc);
4827 } else if (r.IsDelegate && l != r) {
4830 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4831 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4838 no_arg_conv = l == r && !l.IsStruct;
4843 // bool operator != (string a, string b)
4844 // bool operator == (string a, string b)
4846 // bool operator != (Delegate a, Delegate b)
4847 // bool operator == (Delegate a, Delegate b)
4849 // bool operator != (bool a, bool b)
4850 // bool operator == (bool a, bool b)
4852 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4853 // they implement an implicit conversion to any of types above. This does
4854 // not apply when both operands are of same reference type
4856 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4857 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4862 // Now try lifted version of predefined operators
4864 if (no_arg_conv && !l.IsNullableType) {
4866 // Optimizes cases which won't match
4869 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4875 // The == and != operators permit one operand to be a value of a nullable
4876 // type and the other to be the null literal, even if no predefined or user-defined
4877 // operator (in unlifted or lifted form) exists for the operation.
4879 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4880 var lifted = new Nullable.LiftedBinaryOperator (this);
4882 lifted.Right = right;
4883 return lifted.Resolve (ec);
4888 // bool operator != (object a, object b)
4889 // bool operator == (object a, object b)
4891 // An explicit reference conversion exists from the
4892 // type of either operand to the type of the other operand.
4895 // Optimize common path
4897 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4900 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4901 !Convert.ExplicitReferenceConversionExists (r, l))
4904 // Reject allowed explicit conversions like int->object
4905 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4908 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4909 ec.Report.Warning (253, 2, loc,
4910 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4911 l.GetSignatureForError ());
4913 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4914 ec.Report.Warning (252, 2, loc,
4915 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4916 r.GetSignatureForError ());
4922 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4925 // bool operator == (void* x, void* y);
4926 // bool operator != (void* x, void* y);
4927 // bool operator < (void* x, void* y);
4928 // bool operator > (void* x, void* y);
4929 // bool operator <= (void* x, void* y);
4930 // bool operator >= (void* x, void* y);
4932 if ((oper & Operator.ComparisonMask) != 0) {
4935 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4942 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4948 type = ec.BuiltinTypes.Bool;
4952 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4956 // Build-in operators method overloading
4958 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4960 PredefinedOperator best_operator = null;
4961 TypeSpec l = left.Type;
4962 TypeSpec r = right.Type;
4963 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4965 foreach (PredefinedOperator po in operators) {
4966 if ((po.OperatorsMask & oper_mask) == 0)
4969 if (primitives_only) {
4970 if (!po.IsPrimitiveApplicable (l, r))
4973 if (!po.IsApplicable (ec, left, right))
4977 if (best_operator == null) {
4979 if (primitives_only)
4985 best_operator = po.ResolveBetterOperator (ec, best_operator);
4987 if (best_operator == null) {
4988 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4989 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4996 if (best_operator == null)
4999 return best_operator.ConvertResult (ec, this);
5003 // Optimize & constant expressions with 0 value
5005 Expression OptimizeAndOperation (Expression expr)
5007 Constant rc = right as Constant;
5008 Constant lc = left as Constant;
5009 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5011 // The result is a constant with side-effect
5013 Constant side_effect = rc == null ?
5014 new SideEffectConstant (lc, right, loc) :
5015 new SideEffectConstant (rc, left, loc);
5017 return ReducedExpression.Create (side_effect, expr);
5024 // Value types can be compared with the null literal because of the lifting
5025 // language rules. However the result is always true or false.
5027 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5029 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5030 type = rc.BuiltinTypes.Bool;
5034 // FIXME: Handle side effect constants
5035 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5037 if ((Oper & Operator.EqualityMask) != 0) {
5038 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5039 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5041 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5042 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5049 // Performs user-operator overloading
5051 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5053 Expression oper_expr;
5055 var op = ConvertBinaryToUserOperator (oper);
5057 if (l.IsNullableType)
5058 l = Nullable.NullableInfo.GetUnderlyingType (l);
5060 if (r.IsNullableType)
5061 r = Nullable.NullableInfo.GetUnderlyingType (r);
5063 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5064 IList<MemberSpec> right_operators = null;
5067 right_operators = MemberCache.GetUserOperator (r, op, false);
5068 if (right_operators == null && left_operators == null)
5070 } else if (left_operators == null) {
5074 Arguments args = new Arguments (2);
5075 Argument larg = new Argument (left);
5077 Argument rarg = new Argument (right);
5081 // User-defined operator implementations always take precedence
5082 // over predefined operator implementations
5084 if (left_operators != null && right_operators != null) {
5085 left_operators = CombineUserOperators (left_operators, right_operators);
5086 } else if (right_operators != null) {
5087 left_operators = right_operators;
5090 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5091 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5093 var res = new OverloadResolver (left_operators, restr, loc);
5095 var oper_method = res.ResolveOperator (rc, ref args);
5096 if (oper_method == null) {
5098 // Logical && and || cannot be lifted
5100 if ((oper & Operator.LogicalMask) != 0)
5104 // Apply lifted user operators only for liftable types. Implicit conversion
5105 // to nullable types is not allowed
5107 if (!IsLiftedOperatorApplicable ())
5110 // TODO: Cache the result in module container
5111 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5112 if (lifted_methods == null)
5115 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5117 oper_method = res.ResolveOperator (rc, ref args);
5118 if (oper_method == null)
5121 MethodSpec best_original = null;
5122 foreach (MethodSpec ms in left_operators) {
5123 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5129 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5131 // Expression trees use lifted notation in this case
5133 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5134 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5137 var ptypes = best_original.Parameters.Types;
5139 if (left.IsNull || right.IsNull) {
5141 // The lifted operator produces a null value if one or both operands are null
5143 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5144 type = oper_method.ReturnType;
5145 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5149 // The lifted operator produces the value false if one or both operands are null for
5150 // relational operators.
5152 if ((oper & Operator.RelationalMask) != 0) {
5154 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5155 // because return type is actually bool
5157 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5160 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5161 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5165 type = oper_method.ReturnType;
5166 var lifted = new Nullable.LiftedBinaryOperator (this);
5167 lifted.UserOperator = best_original;
5169 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5170 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5173 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5174 lifted.UnwrapRight = new Nullable.Unwrap (right);
5177 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5178 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5180 return lifted.Resolve (rc);
5183 if ((oper & Operator.LogicalMask) != 0) {
5184 // TODO: CreateExpressionTree is allocated every time
5185 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5186 oper == Operator.LogicalAnd, loc).Resolve (rc);
5188 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5191 this.left = larg.Expr;
5192 this.right = rarg.Expr;
5197 bool IsLiftedOperatorApplicable ()
5199 if (left.Type.IsNullableType) {
5200 if ((oper & Operator.EqualityMask) != 0)
5201 return !right.IsNull;
5206 if (right.Type.IsNullableType) {
5207 if ((oper & Operator.EqualityMask) != 0)
5208 return !left.IsNull;
5213 if (TypeSpec.IsValueType (left.Type))
5214 return right.IsNull;
5216 if (TypeSpec.IsValueType (right.Type))
5222 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5224 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5225 if (nullable_type == null)
5229 // Lifted operators permit predefined and user-defined operators that operate
5230 // on non-nullable value types to also be used with nullable forms of those types.
5231 // Lifted operators are constructed from predefined and user-defined operators
5232 // that meet certain requirements
5234 List<MemberSpec> lifted = null;
5235 foreach (MethodSpec oper in operators) {
5237 if ((Oper & Operator.ComparisonMask) != 0) {
5239 // Result type must be of type bool for lifted comparison operators
5241 rt = oper.ReturnType;
5242 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5245 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5251 var ptypes = oper.Parameters.Types;
5252 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5256 // LAMESPEC: I am not sure why but for equality operators to be lifted
5257 // both types have to match
5259 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5263 lifted = new List<MemberSpec> ();
5266 // The lifted form is constructed by adding a single ? modifier to each operand and
5267 // result type except for comparison operators where return type is bool
5270 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5272 var parameters = ParametersCompiled.CreateFullyResolved (
5273 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5274 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5276 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5277 rt, parameters, oper.Modifiers);
5279 lifted.Add (lifted_op);
5286 // Merge two sets of user operators into one, they are mostly distinguish
5287 // except when they share base type and it contains an operator
5289 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5291 var combined = new List<MemberSpec> (left.Count + right.Count);
5292 combined.AddRange (left);
5293 foreach (var r in right) {
5295 foreach (var l in left) {
5296 if (l.DeclaringType == r.DeclaringType) {
5309 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5311 if (c is IntegralConstant || c is CharConstant) {
5313 c.ConvertExplicitly (true, type);
5314 } catch (OverflowException) {
5315 ec.Report.Warning (652, 2, loc,
5316 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5317 type.GetSignatureForError ());
5323 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5324 /// context of a conditional bool expression. This function will return
5325 /// false if it is was possible to use EmitBranchable, or true if it was.
5327 /// The expression's code is generated, and we will generate a branch to `target'
5328 /// if the resulting expression value is equal to isTrue
5330 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5332 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5333 left = left.EmitToField (ec);
5335 if ((oper & Operator.LogicalMask) == 0) {
5336 right = right.EmitToField (ec);
5341 // This is more complicated than it looks, but its just to avoid
5342 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5343 // but on top of that we want for == and != to use a special path
5344 // if we are comparing against null
5346 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5347 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5350 // put the constant on the rhs, for simplicity
5352 if (left is Constant) {
5353 Expression swap = right;
5359 // brtrue/brfalse works with native int only
5361 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5362 left.EmitBranchable (ec, target, my_on_true);
5365 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5366 // right is a boolean, and it's not 'false' => it is 'true'
5367 left.EmitBranchable (ec, target, !my_on_true);
5371 } else if (oper == Operator.LogicalAnd) {
5374 Label tests_end = ec.DefineLabel ();
5376 left.EmitBranchable (ec, tests_end, false);
5377 right.EmitBranchable (ec, target, true);
5378 ec.MarkLabel (tests_end);
5381 // This optimizes code like this
5382 // if (true && i > 4)
5384 if (!(left is Constant))
5385 left.EmitBranchable (ec, target, false);
5387 if (!(right is Constant))
5388 right.EmitBranchable (ec, target, false);
5393 } else if (oper == Operator.LogicalOr){
5395 left.EmitBranchable (ec, target, true);
5396 right.EmitBranchable (ec, target, true);
5399 Label tests_end = ec.DefineLabel ();
5400 left.EmitBranchable (ec, tests_end, true);
5401 right.EmitBranchable (ec, target, false);
5402 ec.MarkLabel (tests_end);
5407 } else if ((oper & Operator.ComparisonMask) == 0) {
5408 base.EmitBranchable (ec, target, on_true);
5415 TypeSpec t = left.Type;
5416 bool is_float = IsFloat (t);
5417 bool is_unsigned = is_float || IsUnsigned (t);
5420 case Operator.Equality:
5422 ec.Emit (OpCodes.Beq, target);
5424 ec.Emit (OpCodes.Bne_Un, target);
5427 case Operator.Inequality:
5429 ec.Emit (OpCodes.Bne_Un, target);
5431 ec.Emit (OpCodes.Beq, target);
5434 case Operator.LessThan:
5436 if (is_unsigned && !is_float)
5437 ec.Emit (OpCodes.Blt_Un, target);
5439 ec.Emit (OpCodes.Blt, target);
5442 ec.Emit (OpCodes.Bge_Un, target);
5444 ec.Emit (OpCodes.Bge, target);
5447 case Operator.GreaterThan:
5449 if (is_unsigned && !is_float)
5450 ec.Emit (OpCodes.Bgt_Un, target);
5452 ec.Emit (OpCodes.Bgt, target);
5455 ec.Emit (OpCodes.Ble_Un, target);
5457 ec.Emit (OpCodes.Ble, target);
5460 case Operator.LessThanOrEqual:
5462 if (is_unsigned && !is_float)
5463 ec.Emit (OpCodes.Ble_Un, target);
5465 ec.Emit (OpCodes.Ble, target);
5468 ec.Emit (OpCodes.Bgt_Un, target);
5470 ec.Emit (OpCodes.Bgt, target);
5474 case Operator.GreaterThanOrEqual:
5476 if (is_unsigned && !is_float)
5477 ec.Emit (OpCodes.Bge_Un, target);
5479 ec.Emit (OpCodes.Bge, target);
5482 ec.Emit (OpCodes.Blt_Un, target);
5484 ec.Emit (OpCodes.Blt, target);
5487 throw new InternalErrorException (oper.ToString ());
5491 public override void Emit (EmitContext ec)
5493 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5494 left = left.EmitToField (ec);
5496 if ((oper & Operator.LogicalMask) == 0) {
5497 right = right.EmitToField (ec);
5502 // Handle short-circuit operators differently
5505 if ((oper & Operator.LogicalMask) != 0) {
5506 Label load_result = ec.DefineLabel ();
5507 Label end = ec.DefineLabel ();
5509 bool is_or = oper == Operator.LogicalOr;
5510 left.EmitBranchable (ec, load_result, is_or);
5512 ec.Emit (OpCodes.Br_S, end);
5514 ec.MarkLabel (load_result);
5515 ec.EmitInt (is_or ? 1 : 0);
5521 // Optimize zero-based operations which cannot be optimized at expression level
5523 if (oper == Operator.Subtraction) {
5524 var lc = left as IntegralConstant;
5525 if (lc != null && lc.IsDefaultValue) {
5527 ec.Emit (OpCodes.Neg);
5532 EmitOperator (ec, left, right);
5535 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5540 EmitOperatorOpcode (ec, oper, left.Type, right);
5543 // Emit result enumerable conversion this way because it's quite complicated get it
5544 // to resolved tree because expression tree cannot see it.
5546 if (enum_conversion != 0)
5547 ConvCast.Emit (ec, enum_conversion);
5550 public override void EmitSideEffect (EmitContext ec)
5552 if ((oper & Operator.LogicalMask) != 0 ||
5553 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5554 base.EmitSideEffect (ec);
5556 left.EmitSideEffect (ec);
5557 right.EmitSideEffect (ec);
5561 public override Expression EmitToField (EmitContext ec)
5563 if ((oper & Operator.LogicalMask) == 0) {
5564 var await_expr = left as Await;
5565 if (await_expr != null && right.IsSideEffectFree) {
5566 await_expr.Statement.EmitPrologue (ec);
5567 left = await_expr.Statement.GetResultExpression (ec);
5571 await_expr = right as Await;
5572 if (await_expr != null && left.IsSideEffectFree) {
5573 await_expr.Statement.EmitPrologue (ec);
5574 right = await_expr.Statement.GetResultExpression (ec);
5579 return base.EmitToField (ec);
5582 protected override void CloneTo (CloneContext clonectx, Expression t)
5584 Binary target = (Binary) t;
5586 target.left = left.Clone (clonectx);
5587 target.right = right.Clone (clonectx);
5590 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5592 Arguments binder_args = new Arguments (4);
5594 MemberAccess sle = new MemberAccess (new MemberAccess (
5595 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5597 CSharpBinderFlags flags = 0;
5598 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5599 flags = CSharpBinderFlags.CheckedContext;
5601 if ((oper & Operator.LogicalMask) != 0)
5602 flags |= CSharpBinderFlags.BinaryOperationLogical;
5604 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5605 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5606 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5607 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5609 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5612 public override Expression CreateExpressionTree (ResolveContext ec)
5614 return CreateExpressionTree (ec, null);
5617 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5620 bool lift_arg = false;
5623 case Operator.Addition:
5624 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5625 method_name = "AddChecked";
5627 method_name = "Add";
5629 case Operator.BitwiseAnd:
5630 method_name = "And";
5632 case Operator.BitwiseOr:
5635 case Operator.Division:
5636 method_name = "Divide";
5638 case Operator.Equality:
5639 method_name = "Equal";
5642 case Operator.ExclusiveOr:
5643 method_name = "ExclusiveOr";
5645 case Operator.GreaterThan:
5646 method_name = "GreaterThan";
5649 case Operator.GreaterThanOrEqual:
5650 method_name = "GreaterThanOrEqual";
5653 case Operator.Inequality:
5654 method_name = "NotEqual";
5657 case Operator.LeftShift:
5658 method_name = "LeftShift";
5660 case Operator.LessThan:
5661 method_name = "LessThan";
5664 case Operator.LessThanOrEqual:
5665 method_name = "LessThanOrEqual";
5668 case Operator.LogicalAnd:
5669 method_name = "AndAlso";
5671 case Operator.LogicalOr:
5672 method_name = "OrElse";
5674 case Operator.Modulus:
5675 method_name = "Modulo";
5677 case Operator.Multiply:
5678 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5679 method_name = "MultiplyChecked";
5681 method_name = "Multiply";
5683 case Operator.RightShift:
5684 method_name = "RightShift";
5686 case Operator.Subtraction:
5687 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5688 method_name = "SubtractChecked";
5690 method_name = "Subtract";
5694 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5697 Arguments args = new Arguments (2);
5698 args.Add (new Argument (left.CreateExpressionTree (ec)));
5699 args.Add (new Argument (right.CreateExpressionTree (ec)));
5700 if (method != null) {
5702 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5704 args.Add (new Argument (method));
5707 return CreateExpressionFactoryCall (ec, method_name, args);
5710 public override object Accept (StructuralVisitor visitor)
5712 return visitor.Visit (this);
5718 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5719 // b, c, d... may be strings or objects.
5721 public class StringConcat : Expression
5723 Arguments arguments;
5725 StringConcat (Location loc)
5728 arguments = new Arguments (2);
5731 public override bool ContainsEmitWithAwait ()
5733 return arguments.ContainsEmitWithAwait ();
5736 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5738 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5739 throw new ArgumentException ();
5741 var s = new StringConcat (loc);
5742 s.type = rc.BuiltinTypes.String;
5743 s.eclass = ExprClass.Value;
5745 s.Append (rc, left);
5746 s.Append (rc, right);
5750 public override Expression CreateExpressionTree (ResolveContext ec)
5752 Argument arg = arguments [0];
5753 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5757 // Creates nested calls tree from an array of arguments used for IL emit
5759 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5761 Arguments concat_args = new Arguments (2);
5762 Arguments add_args = new Arguments (3);
5764 concat_args.Add (left);
5765 add_args.Add (new Argument (left_etree));
5767 concat_args.Add (arguments [pos]);
5768 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5770 var methods = GetConcatMethodCandidates ();
5771 if (methods == null)
5774 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5775 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5779 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5781 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5782 if (++pos == arguments.Count)
5785 left = new Argument (new EmptyExpression (method.ReturnType));
5786 return CreateExpressionAddCall (ec, left, expr, pos);
5789 protected override Expression DoResolve (ResolveContext ec)
5794 void Append (ResolveContext rc, Expression operand)
5799 StringConstant sc = operand as StringConstant;
5801 if (arguments.Count != 0) {
5802 Argument last_argument = arguments [arguments.Count - 1];
5803 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5804 if (last_expr_constant != null) {
5805 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5811 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5813 StringConcat concat_oper = operand as StringConcat;
5814 if (concat_oper != null) {
5815 arguments.AddRange (concat_oper.arguments);
5820 arguments.Add (new Argument (operand));
5823 IList<MemberSpec> GetConcatMethodCandidates ()
5825 return MemberCache.FindMembers (type, "Concat", true);
5828 public override void Emit (EmitContext ec)
5830 // Optimize by removing any extra null arguments, they are no-op
5831 for (int i = 0; i < arguments.Count; ++i) {
5832 if (arguments[i].Expr is NullConstant)
5833 arguments.RemoveAt (i--);
5836 var members = GetConcatMethodCandidates ();
5837 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5838 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5839 if (method != null) {
5840 var call = new CallEmitter ();
5841 call.EmitPredefined (ec, method, arguments, false);
5845 public override void FlowAnalysis (FlowAnalysisContext fc)
5847 arguments.FlowAnalysis (fc);
5850 public override SLE.Expression MakeExpression (BuilderContext ctx)
5852 if (arguments.Count != 2)
5853 throw new NotImplementedException ("arguments.Count != 2");
5855 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5856 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5861 // User-defined conditional logical operator
5863 public class ConditionalLogicalOperator : UserOperatorCall
5865 readonly bool is_and;
5866 Expression oper_expr;
5868 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5869 : base (oper, arguments, expr_tree, loc)
5871 this.is_and = is_and;
5872 eclass = ExprClass.Unresolved;
5875 protected override Expression DoResolve (ResolveContext ec)
5877 AParametersCollection pd = oper.Parameters;
5878 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5879 ec.Report.Error (217, loc,
5880 "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",
5881 oper.GetSignatureForError ());
5885 Expression left_dup = new EmptyExpression (type);
5886 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5887 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5888 if (op_true == null || op_false == null) {
5889 ec.Report.Error (218, loc,
5890 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5891 type.GetSignatureForError (), oper.GetSignatureForError ());
5895 oper_expr = is_and ? op_false : op_true;
5896 eclass = ExprClass.Value;
5900 public override void Emit (EmitContext ec)
5902 Label end_target = ec.DefineLabel ();
5905 // Emit and duplicate left argument
5907 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5908 if (right_contains_await) {
5909 arguments[0] = arguments[0].EmitToField (ec, false);
5910 arguments[0].Expr.Emit (ec);
5912 arguments[0].Expr.Emit (ec);
5913 ec.Emit (OpCodes.Dup);
5914 arguments.RemoveAt (0);
5917 oper_expr.EmitBranchable (ec, end_target, true);
5921 if (right_contains_await) {
5923 // Special handling when right expression contains await and left argument
5924 // could not be left on stack before logical branch
5926 Label skip_left_load = ec.DefineLabel ();
5927 ec.Emit (OpCodes.Br_S, skip_left_load);
5928 ec.MarkLabel (end_target);
5929 arguments[0].Expr.Emit (ec);
5930 ec.MarkLabel (skip_left_load);
5932 ec.MarkLabel (end_target);
5937 public class PointerArithmetic : Expression {
5938 Expression left, right;
5939 readonly Binary.Operator op;
5942 // We assume that `l' is always a pointer
5944 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5953 public override bool ContainsEmitWithAwait ()
5955 throw new NotImplementedException ();
5958 public override Expression CreateExpressionTree (ResolveContext ec)
5960 Error_PointerInsideExpressionTree (ec);
5964 protected override Expression DoResolve (ResolveContext ec)
5966 eclass = ExprClass.Variable;
5968 var pc = left.Type as PointerContainer;
5969 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5970 Error_VoidPointerOperation (ec);
5977 public override void Emit (EmitContext ec)
5979 TypeSpec op_type = left.Type;
5981 // It must be either array or fixed buffer
5983 if (TypeManager.HasElementType (op_type)) {
5984 element = TypeManager.GetElementType (op_type);
5986 FieldExpr fe = left as FieldExpr;
5988 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5993 int size = BuiltinTypeSpec.GetSize(element);
5994 TypeSpec rtype = right.Type;
5996 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5998 // handle (pointer - pointer)
6002 ec.Emit (OpCodes.Sub);
6006 ec.Emit (OpCodes.Sizeof, element);
6009 ec.Emit (OpCodes.Div);
6011 ec.Emit (OpCodes.Conv_I8);
6014 // handle + and - on (pointer op int)
6016 Constant left_const = left as Constant;
6017 if (left_const != null) {
6019 // Optimize ((T*)null) pointer operations
6021 if (left_const.IsDefaultValue) {
6022 left = EmptyExpression.Null;
6030 var right_const = right as Constant;
6031 if (right_const != null) {
6033 // Optimize 0-based arithmetic
6035 if (right_const.IsDefaultValue)
6039 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6041 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6043 // TODO: Should be the checks resolve context sensitive?
6044 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6045 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6051 switch (rtype.BuiltinType) {
6052 case BuiltinTypeSpec.Type.SByte:
6053 case BuiltinTypeSpec.Type.Byte:
6054 case BuiltinTypeSpec.Type.Short:
6055 case BuiltinTypeSpec.Type.UShort:
6056 ec.Emit (OpCodes.Conv_I);
6058 case BuiltinTypeSpec.Type.UInt:
6059 ec.Emit (OpCodes.Conv_U);
6063 if (right_const == null && size != 1){
6065 ec.Emit (OpCodes.Sizeof, element);
6068 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6069 ec.Emit (OpCodes.Conv_I8);
6071 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6074 if (left_const == null) {
6075 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6076 ec.Emit (OpCodes.Conv_I);
6077 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6078 ec.Emit (OpCodes.Conv_U);
6080 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6087 // A boolean-expression is an expression that yields a result
6090 public class BooleanExpression : ShimExpression
6092 public BooleanExpression (Expression expr)
6095 this.loc = expr.Location;
6098 public override Expression CreateExpressionTree (ResolveContext ec)
6100 // TODO: We should emit IsTrue (v4) instead of direct user operator
6101 // call but that would break csc compatibility
6102 return base.CreateExpressionTree (ec);
6105 protected override Expression DoResolve (ResolveContext ec)
6107 // A boolean-expression is required to be of a type
6108 // that can be implicitly converted to bool or of
6109 // a type that implements operator true
6111 expr = expr.Resolve (ec);
6115 Assign ass = expr as Assign;
6116 if (ass != null && ass.Source is Constant) {
6117 ec.Report.Warning (665, 3, loc,
6118 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6121 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6124 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6125 Arguments args = new Arguments (1);
6126 args.Add (new Argument (expr));
6127 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6130 type = ec.BuiltinTypes.Bool;
6131 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6132 if (converted != null)
6136 // If no implicit conversion to bool exists, try using `operator true'
6138 converted = GetOperatorTrue (ec, expr, loc);
6139 if (converted == null) {
6140 expr.Error_ValueCannotBeConverted (ec, type, false);
6147 public override object Accept (StructuralVisitor visitor)
6149 return visitor.Visit (this);
6153 public class BooleanExpressionFalse : Unary
6155 public BooleanExpressionFalse (Expression expr)
6156 : base (Operator.LogicalNot, expr, expr.Location)
6160 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6162 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6167 /// Implements the ternary conditional operator (?:)
6169 public class Conditional : Expression {
6170 Expression expr, true_expr, false_expr;
6172 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6175 this.true_expr = true_expr;
6176 this.false_expr = false_expr;
6182 public Expression Expr {
6188 public Expression TrueExpr {
6194 public Expression FalseExpr {
6202 public override bool ContainsEmitWithAwait ()
6204 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6207 public override Expression CreateExpressionTree (ResolveContext ec)
6209 Arguments args = new Arguments (3);
6210 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6211 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6212 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6213 return CreateExpressionFactoryCall (ec, "Condition", args);
6216 protected override Expression DoResolve (ResolveContext ec)
6218 expr = expr.Resolve (ec);
6219 true_expr = true_expr.Resolve (ec);
6220 false_expr = false_expr.Resolve (ec);
6222 if (true_expr == null || false_expr == null || expr == null)
6225 eclass = ExprClass.Value;
6226 TypeSpec true_type = true_expr.Type;
6227 TypeSpec false_type = false_expr.Type;
6231 // First, if an implicit conversion exists from true_expr
6232 // to false_expr, then the result type is of type false_expr.Type
6234 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6235 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6236 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6238 // Check if both can convert implicitly to each other's type
6242 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6243 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6245 // LAMESPEC: There seems to be hardcoded promotition to int type when
6246 // both sides are numeric constants and one side is int constant and
6247 // other side is numeric constant convertible to int.
6249 // var res = condition ? (short)1 : 1;
6251 // Type of res is int even if according to the spec the conversion is
6252 // ambiguous because 1 literal can be converted to short.
6254 if (conv_false_expr != null) {
6255 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6257 conv_false_expr = null;
6258 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6259 conv_false_expr = null;
6263 if (conv_false_expr != null) {
6264 ec.Report.Error (172, true_expr.Location,
6265 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6266 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6271 if (true_expr.Type != type)
6272 true_expr = EmptyCast.Create (true_expr, type);
6273 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6276 if (false_type != InternalType.ErrorType) {
6277 ec.Report.Error (173, true_expr.Location,
6278 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6279 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6285 Constant c = expr as Constant;
6287 bool is_false = c.IsDefaultValue;
6290 // Don't issue the warning for constant expressions
6292 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6293 // CSC: Missing warning
6294 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6297 return ReducedExpression.Create (
6298 is_false ? false_expr : true_expr, this,
6299 false_expr is Constant && true_expr is Constant).Resolve (ec);
6305 public override void Emit (EmitContext ec)
6307 Label false_target = ec.DefineLabel ();
6308 Label end_target = ec.DefineLabel ();
6310 expr.EmitBranchable (ec, false_target, false);
6311 true_expr.Emit (ec);
6314 // Verifier doesn't support interface merging. When there are two types on
6315 // the stack without common type hint and the common type is an interface.
6316 // Use temporary local to give verifier hint on what type to unify the stack
6318 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6319 var temp = ec.GetTemporaryLocal (type);
6320 ec.Emit (OpCodes.Stloc, temp);
6321 ec.Emit (OpCodes.Ldloc, temp);
6322 ec.FreeTemporaryLocal (temp, type);
6325 ec.Emit (OpCodes.Br, end_target);
6326 ec.MarkLabel (false_target);
6327 false_expr.Emit (ec);
6328 ec.MarkLabel (end_target);
6331 public override void FlowAnalysis (FlowAnalysisContext fc)
6333 expr.FlowAnalysisConditional (fc);
6334 var expr_true = fc.DefiniteAssignmentOnTrue;
6335 var expr_false = fc.DefiniteAssignmentOnFalse;
6337 fc.BranchDefiniteAssignment (expr_true);
6338 true_expr.FlowAnalysis (fc);
6339 var true_fc = fc.DefiniteAssignment;
6341 fc.BranchDefiniteAssignment (expr_false);
6342 false_expr.FlowAnalysis (fc);
6344 fc.DefiniteAssignment &= true_fc;
6347 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6349 expr.FlowAnalysisConditional (fc);
6350 var expr_true = fc.DefiniteAssignmentOnTrue;
6351 var expr_false = fc.DefiniteAssignmentOnFalse;
6353 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6354 true_expr.FlowAnalysisConditional (fc);
6355 var true_fc = fc.DefiniteAssignment;
6356 var true_da_true = fc.DefiniteAssignmentOnTrue;
6357 var true_da_false = fc.DefiniteAssignmentOnFalse;
6359 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6360 false_expr.FlowAnalysisConditional (fc);
6362 fc.DefiniteAssignment &= true_fc;
6363 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6364 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6367 protected override void CloneTo (CloneContext clonectx, Expression t)
6369 Conditional target = (Conditional) t;
6371 target.expr = expr.Clone (clonectx);
6372 target.true_expr = true_expr.Clone (clonectx);
6373 target.false_expr = false_expr.Clone (clonectx);
6377 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6379 LocalTemporary temp;
6382 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6383 public abstract void SetHasAddressTaken ();
6385 public abstract bool IsLockedByStatement { get; set; }
6387 public abstract bool IsFixed { get; }
6388 public abstract bool IsRef { get; }
6389 public abstract string Name { get; }
6392 // Variable IL data, it has to be protected to encapsulate hoisted variables
6394 protected abstract ILocalVariable Variable { get; }
6397 // Variable flow-analysis data
6399 public abstract VariableInfo VariableInfo { get; }
6402 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6404 HoistedVariable hv = GetHoistedVariable (ec);
6406 hv.AddressOf (ec, mode);
6410 Variable.EmitAddressOf (ec);
6413 public override bool ContainsEmitWithAwait ()
6418 public override Expression CreateExpressionTree (ResolveContext ec)
6420 HoistedVariable hv = GetHoistedVariable (ec);
6422 return hv.CreateExpressionTree ();
6424 Arguments arg = new Arguments (1);
6425 arg.Add (new Argument (this));
6426 return CreateExpressionFactoryCall (ec, "Constant", arg);
6429 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6431 if (IsLockedByStatement) {
6432 rc.Report.Warning (728, 2, loc,
6433 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6440 public override void Emit (EmitContext ec)
6445 public override void EmitSideEffect (EmitContext ec)
6451 // This method is used by parameters that are references, that are
6452 // being passed as references: we only want to pass the pointer (that
6453 // is already stored in the parameter, not the address of the pointer,
6454 // and not the value of the variable).
6456 public void EmitLoad (EmitContext ec)
6461 public void Emit (EmitContext ec, bool leave_copy)
6463 HoistedVariable hv = GetHoistedVariable (ec);
6465 hv.Emit (ec, leave_copy);
6473 // If we are a reference, we loaded on the stack a pointer
6474 // Now lets load the real value
6476 ec.EmitLoadFromPtr (type);
6480 ec.Emit (OpCodes.Dup);
6483 temp = new LocalTemporary (Type);
6489 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6490 bool prepare_for_load)
6492 HoistedVariable hv = GetHoistedVariable (ec);
6494 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6498 New n_source = source as New;
6499 if (n_source != null) {
6500 if (!n_source.Emit (ec, this)) {
6504 ec.EmitLoadFromPtr (type);
6516 ec.Emit (OpCodes.Dup);
6518 temp = new LocalTemporary (Type);
6524 ec.EmitStoreFromPtr (type);
6526 Variable.EmitAssign (ec);
6534 public override Expression EmitToField (EmitContext ec)
6536 HoistedVariable hv = GetHoistedVariable (ec);
6538 return hv.EmitToField (ec);
6541 return base.EmitToField (ec);
6544 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6546 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6549 public HoistedVariable GetHoistedVariable (EmitContext ec)
6551 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6554 public override string GetSignatureForError ()
6559 public bool IsHoisted {
6560 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6565 // Resolved reference to a local variable
6567 public class LocalVariableReference : VariableReference
6569 public LocalVariable local_info;
6571 public LocalVariableReference (LocalVariable li, Location l)
6573 this.local_info = li;
6577 public override VariableInfo VariableInfo {
6578 get { return local_info.VariableInfo; }
6581 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6583 return local_info.HoistedVariant;
6589 // A local variable is always fixed
6591 public override bool IsFixed {
6597 public override bool IsLockedByStatement {
6599 return local_info.IsLocked;
6602 local_info.IsLocked = value;
6606 public override bool IsRef {
6607 get { return false; }
6610 public override string Name {
6611 get { return local_info.Name; }
6616 public override void FlowAnalysis (FlowAnalysisContext fc)
6618 VariableInfo variable_info = VariableInfo;
6619 if (variable_info == null)
6622 if (fc.IsDefinitelyAssigned (variable_info))
6625 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6626 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6629 public override void SetHasAddressTaken ()
6631 local_info.SetHasAddressTaken ();
6634 void DoResolveBase (ResolveContext ec)
6636 eclass = ExprClass.Variable;
6637 type = local_info.Type;
6640 // If we are referencing a variable from the external block
6641 // flag it for capturing
6643 if (ec.MustCaptureVariable (local_info)) {
6644 if (local_info.AddressTaken) {
6645 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6646 } else if (local_info.IsFixed) {
6647 ec.Report.Error (1764, loc,
6648 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6649 GetSignatureForError ());
6652 if (ec.IsVariableCapturingRequired) {
6653 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6654 storey.CaptureLocalVariable (ec, local_info);
6659 protected override Expression DoResolve (ResolveContext ec)
6661 local_info.SetIsUsed ();
6665 if (local_info.Type == InternalType.VarOutType) {
6666 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6667 GetSignatureForError ());
6669 type = InternalType.ErrorType;
6675 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6678 // Don't be too pedantic when variable is used as out param or for some broken code
6679 // which uses property/indexer access to run some initialization
6681 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6682 local_info.SetIsUsed ();
6684 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6685 if (rhs == EmptyExpression.LValueMemberAccess) {
6686 // CS1654 already reported
6690 if (rhs == EmptyExpression.OutAccess) {
6691 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6692 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6693 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6694 } else if (rhs == EmptyExpression.UnaryAddress) {
6695 code = 459; msg = "Cannot take the address of {1} `{0}'";
6697 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6699 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6703 if (eclass == ExprClass.Unresolved)
6706 return base.DoResolveLValue (ec, rhs);
6709 public override int GetHashCode ()
6711 return local_info.GetHashCode ();
6714 public override bool Equals (object obj)
6716 LocalVariableReference lvr = obj as LocalVariableReference;
6720 return local_info == lvr.local_info;
6723 protected override ILocalVariable Variable {
6724 get { return local_info; }
6727 public override string ToString ()
6729 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6732 protected override void CloneTo (CloneContext clonectx, Expression t)
6739 /// This represents a reference to a parameter in the intermediate
6742 public class ParameterReference : VariableReference
6744 protected ParametersBlock.ParameterInfo pi;
6746 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6754 public override bool IsLockedByStatement {
6759 pi.IsLocked = value;
6763 public override bool IsRef {
6764 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6767 bool HasOutModifier {
6768 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6771 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6773 return pi.Parameter.HoistedVariant;
6777 // A ref or out parameter is classified as a moveable variable, even
6778 // if the argument given for the parameter is a fixed variable
6780 public override bool IsFixed {
6781 get { return !IsRef; }
6784 public override string Name {
6785 get { return Parameter.Name; }
6788 public Parameter Parameter {
6789 get { return pi.Parameter; }
6792 public override VariableInfo VariableInfo {
6793 get { return pi.VariableInfo; }
6796 protected override ILocalVariable Variable {
6797 get { return Parameter; }
6802 public override void AddressOf (EmitContext ec, AddressOp mode)
6805 // ParameterReferences might already be a reference
6812 base.AddressOf (ec, mode);
6815 public override void SetHasAddressTaken ()
6817 Parameter.HasAddressTaken = true;
6820 bool DoResolveBase (ResolveContext ec)
6822 if (eclass != ExprClass.Unresolved)
6825 type = pi.ParameterType;
6826 eclass = ExprClass.Variable;
6829 // If we are referencing a parameter from the external block
6830 // flag it for capturing
6832 if (ec.MustCaptureVariable (pi)) {
6833 if (Parameter.HasAddressTaken)
6834 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6837 ec.Report.Error (1628, loc,
6838 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6839 Name, ec.CurrentAnonymousMethod.ContainerType);
6842 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6843 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6844 storey.CaptureParameter (ec, pi, this);
6851 public override int GetHashCode ()
6853 return Name.GetHashCode ();
6856 public override bool Equals (object obj)
6858 ParameterReference pr = obj as ParameterReference;
6862 return Name == pr.Name;
6865 protected override void CloneTo (CloneContext clonectx, Expression target)
6871 public override Expression CreateExpressionTree (ResolveContext ec)
6873 HoistedVariable hv = GetHoistedVariable (ec);
6875 return hv.CreateExpressionTree ();
6877 return Parameter.ExpressionTreeVariableReference ();
6880 protected override Expression DoResolve (ResolveContext ec)
6882 if (!DoResolveBase (ec))
6888 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6890 if (!DoResolveBase (ec))
6893 if (Parameter.HoistedVariant != null)
6894 Parameter.HoistedVariant.IsAssigned = true;
6896 return base.DoResolveLValue (ec, right_side);
6899 public override void FlowAnalysis (FlowAnalysisContext fc)
6901 VariableInfo variable_info = VariableInfo;
6902 if (variable_info == null)
6905 if (fc.IsDefinitelyAssigned (variable_info))
6908 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6909 fc.SetVariableAssigned (variable_info);
6914 /// Invocation of methods or delegates.
6916 public class Invocation : ExpressionStatement
6918 public class Predefined : Invocation
6920 public Predefined (MethodGroupExpr expr, Arguments arguments)
6921 : base (expr, arguments)
6926 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6928 mg.BestCandidate.CheckObsoleteness (rc, loc);
6934 protected Arguments arguments;
6935 protected Expression expr;
6936 protected MethodGroupExpr mg;
6937 bool conditional_access_receiver;
6939 public Invocation (Expression expr, Arguments arguments)
6942 this.arguments = arguments;
6944 loc = expr.Location;
6949 public Arguments Arguments {
6955 public Expression Exp {
6961 public MethodGroupExpr MethodGroup {
6967 public override Location StartLocation {
6969 return expr.StartLocation;
6975 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6977 if (MethodGroup == null)
6980 var candidate = MethodGroup.BestCandidate;
6981 if (candidate == null || !(candidate.IsStatic || Exp is This))
6984 var args_count = arguments == null ? 0 : arguments.Count;
6985 if (args_count != body.Parameters.Count)
6988 var lambda_parameters = body.Block.Parameters.FixedParameters;
6989 for (int i = 0; i < args_count; ++i) {
6990 var pr = arguments[i].Expr as ParameterReference;
6994 if (lambda_parameters[i] != pr.Parameter)
6997 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7001 var emg = MethodGroup as ExtensionMethodGroupExpr;
7003 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7004 if (candidate.IsGeneric) {
7005 var targs = new TypeExpression [candidate.Arity];
7006 for (int i = 0; i < targs.Length; ++i) {
7007 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7010 mg.SetTypeArguments (null, new TypeArguments (targs));
7019 protected override void CloneTo (CloneContext clonectx, Expression t)
7021 Invocation target = (Invocation) t;
7023 if (arguments != null)
7024 target.arguments = arguments.Clone (clonectx);
7026 target.expr = expr.Clone (clonectx);
7029 public override bool ContainsEmitWithAwait ()
7031 if (arguments != null && arguments.ContainsEmitWithAwait ())
7034 return mg.ContainsEmitWithAwait ();
7037 public override Expression CreateExpressionTree (ResolveContext ec)
7039 Expression instance = mg.IsInstance ?
7040 mg.InstanceExpression.CreateExpressionTree (ec) :
7041 new NullLiteral (loc);
7043 var args = Arguments.CreateForExpressionTree (ec, arguments,
7045 mg.CreateExpressionTree (ec));
7047 return CreateExpressionFactoryCall (ec, "Call", args);
7050 void ResolveConditionalAccessReceiver (ResolveContext rc)
7052 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7053 conditional_access_receiver = true;
7057 protected override Expression DoResolve (ResolveContext rc)
7059 ResolveConditionalAccessReceiver (rc);
7060 return DoResolveInvocation (rc);
7063 Expression DoResolveInvocation (ResolveContext ec)
7065 Expression member_expr;
7066 var atn = expr as ATypeNameExpression;
7068 var flags = default (ResolveContext.FlagsHandle);
7069 if (conditional_access_receiver)
7070 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7073 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7074 if (member_expr != null) {
7075 var name_of = member_expr as NameOf;
7076 if (name_of != null) {
7077 return name_of.ResolveOverload (ec, arguments);
7080 member_expr = member_expr.Resolve (ec);
7083 member_expr = expr.Resolve (ec);
7086 if (conditional_access_receiver)
7089 if (member_expr == null)
7093 // Next, evaluate all the expressions in the argument list
7095 bool dynamic_arg = false;
7096 if (arguments != null)
7097 arguments.Resolve (ec, out dynamic_arg);
7099 TypeSpec expr_type = member_expr.Type;
7100 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7101 return DoResolveDynamic (ec, member_expr);
7103 mg = member_expr as MethodGroupExpr;
7104 Expression invoke = null;
7107 if (expr_type != null && expr_type.IsDelegate) {
7108 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7109 invoke = invoke.Resolve (ec);
7110 if (invoke == null || !dynamic_arg)
7113 if (member_expr is RuntimeValueExpression) {
7114 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7115 member_expr.Type.GetSignatureForError ());
7119 MemberExpr me = member_expr as MemberExpr;
7121 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7125 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7126 member_expr.GetSignatureForError ());
7131 if (invoke == null) {
7132 mg = DoResolveOverload (ec);
7138 return DoResolveDynamic (ec, member_expr);
7140 var method = mg.BestCandidate;
7141 type = mg.BestCandidateReturnType;
7142 if (conditional_access_receiver)
7143 type = LiftMemberType (ec, type);
7145 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7147 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7149 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7153 IsSpecialMethodInvocation (ec, method, loc);
7155 eclass = ExprClass.Value;
7159 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7162 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7164 args = dmb.Arguments;
7165 if (arguments != null)
7166 args.AddRange (arguments);
7167 } else if (mg == null) {
7168 if (arguments == null)
7169 args = new Arguments (1);
7173 args.Insert (0, new Argument (memberExpr));
7177 ec.Report.Error (1971, loc,
7178 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7183 if (arguments == null)
7184 args = new Arguments (1);
7188 MemberAccess ma = expr as MemberAccess;
7190 var inst = mg.InstanceExpression;
7191 var left_type = inst as TypeExpr;
7192 if (left_type != null) {
7193 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7194 } else if (inst != null) {
7196 // Any value type has to be pass as by-ref to get back the same
7197 // instance on which the member was called
7199 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7200 Argument.AType.Ref : Argument.AType.None;
7201 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7203 } else { // is SimpleName
7205 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7207 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7212 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7215 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7217 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7220 public override void FlowAnalysis (FlowAnalysisContext fc)
7222 if (mg.IsConditionallyExcluded)
7225 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7227 mg.FlowAnalysis (fc);
7229 if (arguments != null)
7230 arguments.FlowAnalysis (fc);
7232 if (conditional_access_receiver)
7233 fc.DefiniteAssignment = da;
7236 public override string GetSignatureForError ()
7238 return mg.GetSignatureForError ();
7241 public override bool HasConditionalAccess ()
7243 return expr.HasConditionalAccess ();
7247 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7248 // or the type dynamic, then the member is invocable
7250 public static bool IsMemberInvocable (MemberSpec member)
7252 switch (member.Kind) {
7253 case MemberKind.Event:
7255 case MemberKind.Field:
7256 case MemberKind.Property:
7257 var m = member as IInterfaceMemberSpec;
7258 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7264 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7266 if (!method.IsReservedMethod)
7269 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7272 ec.Report.SymbolRelatedToPreviousError (method);
7273 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7274 method.GetSignatureForError ());
7279 public override void Emit (EmitContext ec)
7281 if (mg.IsConditionallyExcluded)
7284 if (conditional_access_receiver)
7285 mg.EmitCall (ec, arguments, type, false);
7287 mg.EmitCall (ec, arguments, false);
7290 public override void EmitStatement (EmitContext ec)
7292 if (mg.IsConditionallyExcluded)
7295 if (conditional_access_receiver)
7296 mg.EmitCall (ec, arguments, type, true);
7298 mg.EmitCall (ec, arguments, true);
7301 public override SLE.Expression MakeExpression (BuilderContext ctx)
7303 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7306 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7309 throw new NotSupportedException ();
7311 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7312 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7316 public override object Accept (StructuralVisitor visitor)
7318 return visitor.Visit (this);
7323 // Implements simple new expression
7325 public class New : ExpressionStatement, IMemoryLocation
7327 protected Arguments arguments;
7330 // During bootstrap, it contains the RequestedType,
7331 // but if `type' is not null, it *might* contain a NewDelegate
7332 // (because of field multi-initialization)
7334 protected Expression RequestedType;
7336 protected MethodSpec method;
7338 public New (Expression requested_type, Arguments arguments, Location l)
7340 RequestedType = requested_type;
7341 this.arguments = arguments;
7346 public Arguments Arguments {
7353 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7355 public bool IsGeneratedStructConstructor {
7357 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7361 public Expression TypeExpression {
7363 return RequestedType;
7370 /// Converts complex core type syntax like 'new int ()' to simple constant
7372 public static Constant Constantify (TypeSpec t, Location loc)
7374 switch (t.BuiltinType) {
7375 case BuiltinTypeSpec.Type.Int:
7376 return new IntConstant (t, 0, loc);
7377 case BuiltinTypeSpec.Type.UInt:
7378 return new UIntConstant (t, 0, loc);
7379 case BuiltinTypeSpec.Type.Long:
7380 return new LongConstant (t, 0, loc);
7381 case BuiltinTypeSpec.Type.ULong:
7382 return new ULongConstant (t, 0, loc);
7383 case BuiltinTypeSpec.Type.Float:
7384 return new FloatConstant (t, 0, loc);
7385 case BuiltinTypeSpec.Type.Double:
7386 return new DoubleConstant (t, 0, loc);
7387 case BuiltinTypeSpec.Type.Short:
7388 return new ShortConstant (t, 0, loc);
7389 case BuiltinTypeSpec.Type.UShort:
7390 return new UShortConstant (t, 0, loc);
7391 case BuiltinTypeSpec.Type.SByte:
7392 return new SByteConstant (t, 0, loc);
7393 case BuiltinTypeSpec.Type.Byte:
7394 return new ByteConstant (t, 0, loc);
7395 case BuiltinTypeSpec.Type.Char:
7396 return new CharConstant (t, '\0', loc);
7397 case BuiltinTypeSpec.Type.Bool:
7398 return new BoolConstant (t, false, loc);
7399 case BuiltinTypeSpec.Type.Decimal:
7400 return new DecimalConstant (t, 0, loc);
7404 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7406 if (t.IsNullableType)
7407 return Nullable.LiftedNull.Create (t, loc);
7412 public override bool ContainsEmitWithAwait ()
7414 return arguments != null && arguments.ContainsEmitWithAwait ();
7418 // Checks whether the type is an interface that has the
7419 // [ComImport, CoClass] attributes and must be treated
7422 public Expression CheckComImport (ResolveContext ec)
7424 if (!type.IsInterface)
7428 // Turn the call into:
7429 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7431 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7432 if (real_class == null)
7435 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7436 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7437 return cast.Resolve (ec);
7440 public override Expression CreateExpressionTree (ResolveContext ec)
7443 if (method == null) {
7444 args = new Arguments (1);
7445 args.Add (new Argument (new TypeOf (type, loc)));
7447 args = Arguments.CreateForExpressionTree (ec,
7448 arguments, new TypeOfMethod (method, loc));
7451 return CreateExpressionFactoryCall (ec, "New", args);
7454 protected override Expression DoResolve (ResolveContext ec)
7456 type = RequestedType.ResolveAsType (ec);
7460 eclass = ExprClass.Value;
7462 if (type.IsPointer) {
7463 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7464 type.GetSignatureForError ());
7468 if (arguments == null) {
7469 Constant c = Constantify (type, RequestedType.Location);
7471 return ReducedExpression.Create (c, this);
7474 if (type.IsDelegate) {
7475 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7478 var tparam = type as TypeParameterSpec;
7479 if (tparam != null) {
7481 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7482 // where type parameter constraint is inflated to struct
7484 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7485 ec.Report.Error (304, loc,
7486 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7487 type.GetSignatureForError ());
7490 if ((arguments != null) && (arguments.Count != 0)) {
7491 ec.Report.Error (417, loc,
7492 "`{0}': cannot provide arguments when creating an instance of a variable type",
7493 type.GetSignatureForError ());
7499 if (type.IsStatic) {
7500 ec.Report.SymbolRelatedToPreviousError (type);
7501 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7505 if (type.IsInterface || type.IsAbstract){
7506 if (!TypeManager.IsGenericType (type)) {
7507 RequestedType = CheckComImport (ec);
7508 if (RequestedType != null)
7509 return RequestedType;
7512 ec.Report.SymbolRelatedToPreviousError (type);
7513 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7518 if (arguments != null) {
7519 arguments.Resolve (ec, out dynamic);
7524 method = ConstructorLookup (ec, type, ref arguments, loc);
7527 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7528 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7534 void DoEmitTypeParameter (EmitContext ec)
7536 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7540 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7541 ec.Emit (OpCodes.Call, ctor_factory);
7545 // This Emit can be invoked in two contexts:
7546 // * As a mechanism that will leave a value on the stack (new object)
7547 // * As one that wont (init struct)
7549 // If we are dealing with a ValueType, we have a few
7550 // situations to deal with:
7552 // * The target is a ValueType, and we have been provided
7553 // the instance (this is easy, we are being assigned).
7555 // * The target of New is being passed as an argument,
7556 // to a boxing operation or a function that takes a
7559 // In this case, we need to create a temporary variable
7560 // that is the argument of New.
7562 // Returns whether a value is left on the stack
7564 // *** Implementation note ***
7566 // To benefit from this optimization, each assignable expression
7567 // has to manually cast to New and call this Emit.
7569 // TODO: It's worth to implement it for arrays and fields
7571 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7573 bool is_value_type = type.IsStructOrEnum;
7574 VariableReference vr = target as VariableReference;
7576 if (target != null && is_value_type && (vr != null || method == null)) {
7577 target.AddressOf (ec, AddressOp.Store);
7578 } else if (vr != null && vr.IsRef) {
7582 if (arguments != null) {
7583 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7584 arguments = arguments.Emit (ec, false, true);
7586 arguments.Emit (ec);
7589 if (is_value_type) {
7590 if (method == null) {
7591 ec.Emit (OpCodes.Initobj, type);
7596 ec.MarkCallEntry (loc);
7597 ec.Emit (OpCodes.Call, method);
7602 if (type is TypeParameterSpec) {
7603 DoEmitTypeParameter (ec);
7607 ec.MarkCallEntry (loc);
7608 ec.Emit (OpCodes.Newobj, method);
7612 public override void Emit (EmitContext ec)
7614 LocalTemporary v = null;
7615 if (method == null && type.IsStructOrEnum) {
7616 // TODO: Use temporary variable from pool
7617 v = new LocalTemporary (type);
7624 public override void EmitStatement (EmitContext ec)
7626 LocalTemporary v = null;
7627 if (method == null && TypeSpec.IsValueType (type)) {
7628 // TODO: Use temporary variable from pool
7629 v = new LocalTemporary (type);
7633 ec.Emit (OpCodes.Pop);
7636 public override void FlowAnalysis (FlowAnalysisContext fc)
7638 if (arguments != null)
7639 arguments.FlowAnalysis (fc);
7642 public void AddressOf (EmitContext ec, AddressOp mode)
7644 EmitAddressOf (ec, mode);
7647 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7649 LocalTemporary value_target = new LocalTemporary (type);
7651 if (type is TypeParameterSpec) {
7652 DoEmitTypeParameter (ec);
7653 value_target.Store (ec);
7654 value_target.AddressOf (ec, mode);
7655 return value_target;
7658 value_target.AddressOf (ec, AddressOp.Store);
7660 if (method == null) {
7661 ec.Emit (OpCodes.Initobj, type);
7663 if (arguments != null)
7664 arguments.Emit (ec);
7666 ec.Emit (OpCodes.Call, method);
7669 value_target.AddressOf (ec, mode);
7670 return value_target;
7673 protected override void CloneTo (CloneContext clonectx, Expression t)
7675 New target = (New) t;
7677 target.RequestedType = RequestedType.Clone (clonectx);
7678 if (arguments != null){
7679 target.arguments = arguments.Clone (clonectx);
7683 public override SLE.Expression MakeExpression (BuilderContext ctx)
7686 return base.MakeExpression (ctx);
7688 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7692 public override object Accept (StructuralVisitor visitor)
7694 return visitor.Visit (this);
7699 // Array initializer expression, the expression is allowed in
7700 // variable or field initialization only which makes it tricky as
7701 // the type has to be infered based on the context either from field
7702 // type or variable type (think of multiple declarators)
7704 public class ArrayInitializer : Expression
7706 List<Expression> elements;
7707 BlockVariable variable;
7709 public ArrayInitializer (List<Expression> init, Location loc)
7715 public ArrayInitializer (int count, Location loc)
7716 : this (new List<Expression> (count), loc)
7720 public ArrayInitializer (Location loc)
7728 get { return elements.Count; }
7731 public List<Expression> Elements {
7737 public Expression this [int index] {
7739 return elements [index];
7743 public BlockVariable VariableDeclaration {
7754 public void Add (Expression expr)
7756 elements.Add (expr);
7759 public override bool ContainsEmitWithAwait ()
7761 throw new NotSupportedException ();
7764 public override Expression CreateExpressionTree (ResolveContext ec)
7766 throw new NotSupportedException ("ET");
7769 protected override void CloneTo (CloneContext clonectx, Expression t)
7771 var target = (ArrayInitializer) t;
7773 target.elements = new List<Expression> (elements.Count);
7774 foreach (var element in elements)
7775 target.elements.Add (element.Clone (clonectx));
7778 protected override Expression DoResolve (ResolveContext rc)
7780 var current_field = rc.CurrentMemberDefinition as FieldBase;
7781 TypeExpression type;
7782 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7783 type = new TypeExpression (current_field.MemberType, current_field.Location);
7784 } else if (variable != null) {
7785 if (variable.TypeExpression is VarExpr) {
7786 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7787 return EmptyExpression.Null;
7790 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7792 throw new NotImplementedException ("Unexpected array initializer context");
7795 return new ArrayCreation (type, this).Resolve (rc);
7798 public override void Emit (EmitContext ec)
7800 throw new InternalErrorException ("Missing Resolve call");
7803 public override void FlowAnalysis (FlowAnalysisContext fc)
7805 throw new InternalErrorException ("Missing Resolve call");
7808 public override object Accept (StructuralVisitor visitor)
7810 return visitor.Visit (this);
7815 /// 14.5.10.2: Represents an array creation expression.
7819 /// There are two possible scenarios here: one is an array creation
7820 /// expression that specifies the dimensions and optionally the
7821 /// initialization data and the other which does not need dimensions
7822 /// specified but where initialization data is mandatory.
7824 public class ArrayCreation : Expression
7826 FullNamedExpression requested_base_type;
7827 ArrayInitializer initializers;
7830 // The list of Argument types.
7831 // This is used to construct the `newarray' or constructor signature
7833 protected List<Expression> arguments;
7835 protected TypeSpec array_element_type;
7837 protected int dimensions;
7838 protected readonly ComposedTypeSpecifier rank;
7839 Expression first_emit;
7840 LocalTemporary first_emit_temp;
7842 protected List<Expression> array_data;
7844 Dictionary<int, int> bounds;
7847 // The number of constants in array initializers
7848 int const_initializers_count;
7849 bool only_constant_initializers;
7851 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7852 : this (requested_base_type, rank, initializers, l)
7854 arguments = new List<Expression> (exprs);
7855 num_arguments = arguments.Count;
7859 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7861 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7863 this.requested_base_type = requested_base_type;
7865 this.initializers = initializers;
7869 num_arguments = rank.Dimension;
7873 // For compiler generated single dimensional arrays only
7875 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7876 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7881 // For expressions like int[] foo = { 1, 2, 3 };
7883 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7884 : this (requested_base_type, null, initializers, initializers.Location)
7888 public ComposedTypeSpecifier Rank {
7894 public FullNamedExpression TypeExpression {
7896 return this.requested_base_type;
7900 public ArrayInitializer Initializers {
7902 return this.initializers;
7906 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7908 if (initializers != null && bounds == null) {
7910 // We use this to store all the data values in the order in which we
7911 // will need to store them in the byte blob later
7913 array_data = new List<Expression> (probe.Count);
7914 bounds = new Dictionary<int, int> ();
7917 if (specified_dims) {
7918 Expression a = arguments [idx];
7923 a = ConvertExpressionToArrayIndex (ec, a);
7929 if (initializers != null) {
7930 Constant c = a as Constant;
7931 if (c == null && a is ArrayIndexCast)
7932 c = ((ArrayIndexCast) a).Child as Constant;
7935 ec.Report.Error (150, a.Location, "A constant value is expected");
7941 value = System.Convert.ToInt32 (c.GetValue ());
7943 ec.Report.Error (150, a.Location, "A constant value is expected");
7947 // TODO: probe.Count does not fit ulong in
7948 if (value != probe.Count) {
7949 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7953 bounds[idx] = value;
7957 if (initializers == null)
7960 for (int i = 0; i < probe.Count; ++i) {
7962 if (o is ArrayInitializer) {
7963 var sub_probe = o as ArrayInitializer;
7964 if (idx + 1 >= dimensions){
7965 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7969 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7970 if (!bounds.ContainsKey(idx + 1))
7971 bounds[idx + 1] = sub_probe.Count;
7973 if (bounds[idx + 1] != sub_probe.Count) {
7974 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7978 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7981 } else if (child_bounds > 1) {
7982 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7984 Expression element = ResolveArrayElement (ec, o);
7985 if (element == null)
7988 // Initializers with the default values can be ignored
7989 Constant c = element as Constant;
7991 if (!c.IsDefaultInitializer (array_element_type)) {
7992 ++const_initializers_count;
7995 only_constant_initializers = false;
7998 array_data.Add (element);
8005 public override bool ContainsEmitWithAwait ()
8007 foreach (var arg in arguments) {
8008 if (arg.ContainsEmitWithAwait ())
8012 return InitializersContainAwait ();
8015 public override Expression CreateExpressionTree (ResolveContext ec)
8019 if (array_data == null) {
8020 args = new Arguments (arguments.Count + 1);
8021 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8022 foreach (Expression a in arguments)
8023 args.Add (new Argument (a.CreateExpressionTree (ec)));
8025 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8028 if (dimensions > 1) {
8029 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8033 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8034 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8035 if (array_data != null) {
8036 for (int i = 0; i < array_data.Count; ++i) {
8037 Expression e = array_data [i];
8038 args.Add (new Argument (e.CreateExpressionTree (ec)));
8042 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8045 void UpdateIndices (ResolveContext rc)
8048 for (var probe = initializers; probe != null;) {
8049 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8051 bounds[i++] = probe.Count;
8053 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8054 probe = (ArrayInitializer) probe[0];
8055 } else if (dimensions > i) {
8063 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8065 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8068 public override void FlowAnalysis (FlowAnalysisContext fc)
8070 foreach (var arg in arguments)
8071 arg.FlowAnalysis (fc);
8073 if (array_data != null) {
8074 foreach (var ad in array_data)
8075 ad.FlowAnalysis (fc);
8079 bool InitializersContainAwait ()
8081 if (array_data == null)
8084 foreach (var expr in array_data) {
8085 if (expr.ContainsEmitWithAwait ())
8092 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8094 element = element.Resolve (ec);
8095 if (element == null)
8098 if (element is CompoundAssign.TargetExpression) {
8099 if (first_emit != null)
8100 throw new InternalErrorException ("Can only handle one mutator at a time");
8101 first_emit = element;
8102 element = first_emit_temp = new LocalTemporary (element.Type);
8105 return Convert.ImplicitConversionRequired (
8106 ec, element, array_element_type, loc);
8109 protected bool ResolveInitializers (ResolveContext ec)
8112 only_constant_initializers = true;
8115 if (arguments != null) {
8117 for (int i = 0; i < arguments.Count; ++i) {
8118 res &= CheckIndices (ec, initializers, i, true, dimensions);
8119 if (initializers != null)
8126 arguments = new List<Expression> ();
8128 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8137 // Resolved the type of the array
8139 bool ResolveArrayType (ResolveContext ec)
8144 FullNamedExpression array_type_expr;
8145 if (num_arguments > 0) {
8146 array_type_expr = new ComposedCast (requested_base_type, rank);
8148 array_type_expr = requested_base_type;
8151 type = array_type_expr.ResolveAsType (ec);
8152 if (array_type_expr == null)
8155 var ac = type as ArrayContainer;
8157 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8161 array_element_type = ac.Element;
8162 dimensions = ac.Rank;
8167 protected override Expression DoResolve (ResolveContext ec)
8172 if (!ResolveArrayType (ec))
8176 // validate the initializers and fill in any missing bits
8178 if (!ResolveInitializers (ec))
8181 eclass = ExprClass.Value;
8185 byte [] MakeByteBlob ()
8190 int count = array_data.Count;
8192 TypeSpec element_type = array_element_type;
8193 if (element_type.IsEnum)
8194 element_type = EnumSpec.GetUnderlyingType (element_type);
8196 factor = BuiltinTypeSpec.GetSize (element_type);
8198 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8200 data = new byte [(count * factor + 3) & ~3];
8203 for (int i = 0; i < count; ++i) {
8204 var c = array_data[i] as Constant;
8210 object v = c.GetValue ();
8212 switch (element_type.BuiltinType) {
8213 case BuiltinTypeSpec.Type.Long:
8214 long lval = (long) v;
8216 for (int j = 0; j < factor; ++j) {
8217 data[idx + j] = (byte) (lval & 0xFF);
8221 case BuiltinTypeSpec.Type.ULong:
8222 ulong ulval = (ulong) v;
8224 for (int j = 0; j < factor; ++j) {
8225 data[idx + j] = (byte) (ulval & 0xFF);
8226 ulval = (ulval >> 8);
8229 case BuiltinTypeSpec.Type.Float:
8230 var fval = SingleConverter.SingleToInt32Bits((float) v);
8232 data[idx] = (byte) (fval & 0xff);
8233 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8234 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8235 data[idx + 3] = (byte) (fval >> 24);
8237 case BuiltinTypeSpec.Type.Double:
8238 element = BitConverter.GetBytes ((double) v);
8240 for (int j = 0; j < factor; ++j)
8241 data[idx + j] = element[j];
8243 // FIXME: Handle the ARM float format.
8244 if (!BitConverter.IsLittleEndian)
8245 System.Array.Reverse (data, idx, 8);
8247 case BuiltinTypeSpec.Type.Char:
8248 int chval = (int) ((char) v);
8250 data[idx] = (byte) (chval & 0xff);
8251 data[idx + 1] = (byte) (chval >> 8);
8253 case BuiltinTypeSpec.Type.Short:
8254 int sval = (int) ((short) v);
8256 data[idx] = (byte) (sval & 0xff);
8257 data[idx + 1] = (byte) (sval >> 8);
8259 case BuiltinTypeSpec.Type.UShort:
8260 int usval = (int) ((ushort) v);
8262 data[idx] = (byte) (usval & 0xff);
8263 data[idx + 1] = (byte) (usval >> 8);
8265 case BuiltinTypeSpec.Type.Int:
8268 data[idx] = (byte) (val & 0xff);
8269 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8270 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8271 data[idx + 3] = (byte) (val >> 24);
8273 case BuiltinTypeSpec.Type.UInt:
8274 uint uval = (uint) v;
8276 data[idx] = (byte) (uval & 0xff);
8277 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8278 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8279 data[idx + 3] = (byte) (uval >> 24);
8281 case BuiltinTypeSpec.Type.SByte:
8282 data[idx] = (byte) (sbyte) v;
8284 case BuiltinTypeSpec.Type.Byte:
8285 data[idx] = (byte) v;
8287 case BuiltinTypeSpec.Type.Bool:
8288 data[idx] = (byte) ((bool) v ? 1 : 0);
8290 case BuiltinTypeSpec.Type.Decimal:
8291 int[] bits = Decimal.GetBits ((decimal) v);
8294 // FIXME: For some reason, this doesn't work on the MS runtime.
8295 int[] nbits = new int[4];
8301 for (int j = 0; j < 4; j++) {
8302 data[p++] = (byte) (nbits[j] & 0xff);
8303 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8304 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8305 data[p++] = (byte) (nbits[j] >> 24);
8309 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8318 public override SLE.Expression MakeExpression (BuilderContext ctx)
8321 return base.MakeExpression (ctx);
8323 var initializers = new SLE.Expression [array_data.Count];
8324 for (var i = 0; i < initializers.Length; i++) {
8325 if (array_data [i] == null)
8326 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8328 initializers [i] = array_data [i].MakeExpression (ctx);
8331 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8336 // Emits the initializers for the array
8338 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8340 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8345 // First, the static data
8347 byte [] data = MakeByteBlob ();
8348 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8350 if (stackArray == null) {
8351 ec.Emit (OpCodes.Dup);
8353 stackArray.Emit (ec);
8356 ec.Emit (OpCodes.Ldtoken, fb);
8357 ec.Emit (OpCodes.Call, m);
8362 // Emits pieces of the array that can not be computed at compile
8363 // time (variables and string locations).
8365 // This always expect the top value on the stack to be the array
8367 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8369 int dims = bounds.Count;
8370 var current_pos = new int [dims];
8372 for (int i = 0; i < array_data.Count; i++){
8374 Expression e = array_data [i];
8375 var c = e as Constant;
8377 // Constant can be initialized via StaticInitializer
8378 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8382 if (stackArray != null) {
8383 if (e.ContainsEmitWithAwait ()) {
8384 e = e.EmitToField (ec);
8387 stackArray.EmitLoad (ec);
8389 ec.Emit (OpCodes.Dup);
8392 for (int idx = 0; idx < dims; idx++)
8393 ec.EmitInt (current_pos [idx]);
8396 // If we are dealing with a struct, get the
8397 // address of it, so we can store it.
8399 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8400 ec.Emit (OpCodes.Ldelema, etype);
8404 ec.EmitArrayStore ((ArrayContainer) type);
8410 for (int j = dims - 1; j >= 0; j--){
8412 if (current_pos [j] < bounds [j])
8414 current_pos [j] = 0;
8418 if (stackArray != null)
8419 stackArray.PrepareCleanup (ec);
8422 public override void Emit (EmitContext ec)
8424 var await_field = EmitToFieldSource (ec);
8425 if (await_field != null)
8426 await_field.Emit (ec);
8429 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8431 if (first_emit != null) {
8432 first_emit.Emit (ec);
8433 first_emit_temp.Store (ec);
8436 StackFieldExpr await_stack_field;
8437 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8438 await_stack_field = ec.GetTemporaryField (type);
8441 await_stack_field = null;
8444 EmitExpressionsList (ec, arguments);
8446 ec.EmitArrayNew ((ArrayContainer) type);
8448 if (initializers == null)
8449 return await_stack_field;
8451 if (await_stack_field != null)
8452 await_stack_field.EmitAssignFromStack (ec);
8456 // Emit static initializer for arrays which contain more than 2 items and
8457 // the static initializer will initialize at least 25% of array values or there
8458 // is more than 10 items to be initialized
8460 // NOTE: const_initializers_count does not contain default constant values.
8462 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8463 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8464 EmitStaticInitializers (ec, await_stack_field);
8466 if (!only_constant_initializers)
8467 EmitDynamicInitializers (ec, false, await_stack_field);
8471 EmitDynamicInitializers (ec, true, await_stack_field);
8474 if (first_emit_temp != null)
8475 first_emit_temp.Release (ec);
8477 return await_stack_field;
8480 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8482 // no multi dimensional or jagged arrays
8483 if (arguments.Count != 1 || array_element_type.IsArray) {
8484 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8488 // No array covariance, except for array -> object
8489 if (type != targetType) {
8490 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8491 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8495 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8496 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8501 // Single dimensional array of 0 size
8502 if (array_data == null) {
8503 IntConstant ic = arguments[0] as IntConstant;
8504 if (ic == null || !ic.IsDefaultValue) {
8505 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8513 enc.Encode (array_data.Count);
8514 foreach (var element in array_data) {
8515 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8519 protected override void CloneTo (CloneContext clonectx, Expression t)
8521 ArrayCreation target = (ArrayCreation) t;
8523 if (requested_base_type != null)
8524 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8526 if (arguments != null){
8527 target.arguments = new List<Expression> (arguments.Count);
8528 foreach (Expression e in arguments)
8529 target.arguments.Add (e.Clone (clonectx));
8532 if (initializers != null)
8533 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8536 public override object Accept (StructuralVisitor visitor)
8538 return visitor.Visit (this);
8543 // Represents an implicitly typed array epxression
8545 class ImplicitlyTypedArrayCreation : ArrayCreation
8547 TypeInferenceContext best_type_inference;
8549 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8550 : base (null, rank, initializers, loc)
8554 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8555 : base (null, initializers, loc)
8559 protected override Expression DoResolve (ResolveContext ec)
8564 dimensions = rank.Dimension;
8566 best_type_inference = new TypeInferenceContext ();
8568 if (!ResolveInitializers (ec))
8571 best_type_inference.FixAllTypes (ec);
8572 array_element_type = best_type_inference.InferredTypeArguments[0];
8573 best_type_inference = null;
8575 if (array_element_type == null ||
8576 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8577 arguments.Count != rank.Dimension) {
8578 ec.Report.Error (826, loc,
8579 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8584 // At this point we found common base type for all initializer elements
8585 // but we have to be sure that all static initializer elements are of
8588 UnifyInitializerElement (ec);
8590 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8591 eclass = ExprClass.Value;
8596 // Converts static initializer only
8598 void UnifyInitializerElement (ResolveContext ec)
8600 for (int i = 0; i < array_data.Count; ++i) {
8601 Expression e = array_data[i];
8603 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8607 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8609 element = element.Resolve (ec);
8610 if (element != null)
8611 best_type_inference.AddCommonTypeBound (element.Type);
8617 sealed class CompilerGeneratedThis : This
8619 public CompilerGeneratedThis (TypeSpec type, Location loc)
8625 protected override Expression DoResolve (ResolveContext rc)
8627 eclass = ExprClass.Variable;
8629 var block = rc.CurrentBlock;
8630 if (block != null) {
8631 var top = block.ParametersBlock.TopBlock;
8632 if (top.ThisVariable != null)
8633 variable_info = top.ThisVariable.VariableInfo;
8640 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8642 return DoResolve (rc);
8645 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8652 /// Represents the `this' construct
8655 public class This : VariableReference
8657 sealed class ThisVariable : ILocalVariable
8659 public static readonly ILocalVariable Instance = new ThisVariable ();
8661 public void Emit (EmitContext ec)
8666 public void EmitAssign (EmitContext ec)
8668 throw new InvalidOperationException ();
8671 public void EmitAddressOf (EmitContext ec)
8677 protected VariableInfo variable_info;
8679 public This (Location loc)
8686 public override string Name {
8687 get { return "this"; }
8690 public override bool IsLockedByStatement {
8698 public override bool IsRef {
8699 get { return type.IsStruct; }
8702 public override bool IsSideEffectFree {
8708 protected override ILocalVariable Variable {
8709 get { return ThisVariable.Instance; }
8712 public override VariableInfo VariableInfo {
8713 get { return variable_info; }
8716 public override bool IsFixed {
8717 get { return false; }
8722 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8725 // It's null for all cases when we don't need to check `this'
8726 // definitive assignment
8728 if (variable_info == null)
8731 if (fc.IsDefinitelyAssigned (variable_info))
8734 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8737 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8739 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8740 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8741 } else if (ec.CurrentAnonymousMethod != null) {
8742 ec.Report.Error (1673, loc,
8743 "Anonymous methods inside structs cannot access instance members of `this'. " +
8744 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8746 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8750 public override void FlowAnalysis (FlowAnalysisContext fc)
8752 CheckStructThisDefiniteAssignment (fc);
8755 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8760 AnonymousMethodStorey storey = ae.Storey;
8761 return storey != null ? storey.HoistedThis : null;
8764 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8766 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8769 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8772 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8778 public virtual void ResolveBase (ResolveContext ec)
8780 eclass = ExprClass.Variable;
8781 type = ec.CurrentType;
8783 if (!IsThisAvailable (ec, false)) {
8784 Error_ThisNotAvailable (ec);
8788 var block = ec.CurrentBlock;
8789 if (block != null) {
8790 var top = block.ParametersBlock.TopBlock;
8791 if (top.ThisVariable != null)
8792 variable_info = top.ThisVariable.VariableInfo;
8794 AnonymousExpression am = ec.CurrentAnonymousMethod;
8795 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8797 // Hoisted this is almost like hoisted variable but not exactly. When
8798 // there is no variable hoisted we can simply emit an instance method
8799 // without lifting this into a storey. Unfotunatelly this complicates
8800 // things in other cases because we don't know where this will be hoisted
8801 // until top-level block is fully resolved
8803 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8804 am.SetHasThisAccess ();
8809 protected override Expression DoResolve (ResolveContext ec)
8815 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8817 if (eclass == ExprClass.Unresolved)
8821 if (right_side == EmptyExpression.UnaryAddress)
8822 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8823 else if (right_side == EmptyExpression.OutAccess)
8824 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8826 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8832 public override int GetHashCode()
8834 throw new NotImplementedException ();
8837 public override bool Equals (object obj)
8839 This t = obj as This;
8846 protected override void CloneTo (CloneContext clonectx, Expression t)
8851 public override void SetHasAddressTaken ()
8856 public override object Accept (StructuralVisitor visitor)
8858 return visitor.Visit (this);
8863 /// Represents the `__arglist' construct
8865 public class ArglistAccess : Expression
8867 public ArglistAccess (Location loc)
8872 protected override void CloneTo (CloneContext clonectx, Expression target)
8877 public override bool ContainsEmitWithAwait ()
8882 public override Expression CreateExpressionTree (ResolveContext ec)
8884 throw new NotSupportedException ("ET");
8887 protected override Expression DoResolve (ResolveContext ec)
8889 eclass = ExprClass.Variable;
8890 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8892 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8893 ec.Report.Error (190, loc,
8894 "The __arglist construct is valid only within a variable argument method");
8900 public override void Emit (EmitContext ec)
8902 ec.Emit (OpCodes.Arglist);
8905 public override object Accept (StructuralVisitor visitor)
8907 return visitor.Visit (this);
8912 /// Represents the `__arglist (....)' construct
8914 public class Arglist : Expression
8916 Arguments arguments;
8918 public Arglist (Location loc)
8923 public Arglist (Arguments args, Location l)
8929 public Arguments Arguments {
8935 public MetaType[] ArgumentTypes {
8937 if (arguments == null)
8938 return MetaType.EmptyTypes;
8940 var retval = new MetaType[arguments.Count];
8941 for (int i = 0; i < retval.Length; i++)
8942 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8948 public override bool ContainsEmitWithAwait ()
8950 throw new NotImplementedException ();
8953 public override Expression CreateExpressionTree (ResolveContext ec)
8955 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8959 protected override Expression DoResolve (ResolveContext ec)
8961 eclass = ExprClass.Variable;
8962 type = InternalType.Arglist;
8963 if (arguments != null) {
8964 bool dynamic; // Can be ignored as there is always only 1 overload
8965 arguments.Resolve (ec, out dynamic);
8971 public override void Emit (EmitContext ec)
8973 if (arguments != null)
8974 arguments.Emit (ec);
8977 protected override void CloneTo (CloneContext clonectx, Expression t)
8979 Arglist target = (Arglist) t;
8981 if (arguments != null)
8982 target.arguments = arguments.Clone (clonectx);
8985 public override object Accept (StructuralVisitor visitor)
8987 return visitor.Visit (this);
8991 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8993 FullNamedExpression texpr;
8995 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9002 public FullNamedExpression TypeExpression {
9008 public override bool ContainsEmitWithAwait ()
9013 public void AddressOf (EmitContext ec, AddressOp mode)
9016 ec.Emit (OpCodes.Refanyval, type);
9019 protected override Expression DoResolve (ResolveContext rc)
9021 expr = expr.Resolve (rc);
9022 type = texpr.ResolveAsType (rc);
9023 if (expr == null || type == null)
9026 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9027 eclass = ExprClass.Variable;
9031 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9033 return DoResolve (rc);
9036 public override void Emit (EmitContext ec)
9039 ec.Emit (OpCodes.Refanyval, type);
9040 ec.EmitLoadFromPtr (type);
9043 public void Emit (EmitContext ec, bool leave_copy)
9045 throw new NotImplementedException ();
9048 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9051 ec.Emit (OpCodes.Refanyval, type);
9054 LocalTemporary temporary = null;
9056 ec.Emit (OpCodes.Dup);
9057 temporary = new LocalTemporary (source.Type);
9058 temporary.Store (ec);
9061 ec.EmitStoreFromPtr (type);
9063 if (temporary != null) {
9064 temporary.Emit (ec);
9065 temporary.Release (ec);
9069 public override object Accept (StructuralVisitor visitor)
9071 return visitor.Visit (this);
9075 public class RefTypeExpr : ShimExpression
9077 public RefTypeExpr (Expression expr, Location loc)
9083 protected override Expression DoResolve (ResolveContext rc)
9085 expr = expr.Resolve (rc);
9089 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9093 type = rc.BuiltinTypes.Type;
9094 eclass = ExprClass.Value;
9098 public override void Emit (EmitContext ec)
9101 ec.Emit (OpCodes.Refanytype);
9102 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9104 ec.Emit (OpCodes.Call, m);
9107 public override object Accept (StructuralVisitor visitor)
9109 return visitor.Visit (this);
9113 public class MakeRefExpr : ShimExpression
9115 public MakeRefExpr (Expression expr, Location loc)
9121 public override bool ContainsEmitWithAwait ()
9123 throw new NotImplementedException ();
9126 protected override Expression DoResolve (ResolveContext rc)
9128 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9129 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9130 eclass = ExprClass.Value;
9134 public override void Emit (EmitContext ec)
9136 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9137 ec.Emit (OpCodes.Mkrefany, expr.Type);
9140 public override object Accept (StructuralVisitor visitor)
9142 return visitor.Visit (this);
9147 /// Implements the typeof operator
9149 public class TypeOf : Expression {
9150 FullNamedExpression QueriedType;
9153 public TypeOf (FullNamedExpression queried_type, Location l)
9155 QueriedType = queried_type;
9160 // Use this constructor for any compiler generated typeof expression
9162 public TypeOf (TypeSpec type, Location loc)
9164 this.typearg = type;
9170 public override bool IsSideEffectFree {
9176 public TypeSpec TypeArgument {
9182 public FullNamedExpression TypeExpression {
9191 protected override void CloneTo (CloneContext clonectx, Expression t)
9193 TypeOf target = (TypeOf) t;
9194 if (QueriedType != null)
9195 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9198 public override bool ContainsEmitWithAwait ()
9203 public override Expression CreateExpressionTree (ResolveContext ec)
9205 Arguments args = new Arguments (2);
9206 args.Add (new Argument (this));
9207 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9208 return CreateExpressionFactoryCall (ec, "Constant", args);
9211 protected override Expression DoResolve (ResolveContext ec)
9213 if (eclass != ExprClass.Unresolved)
9216 if (typearg == null) {
9218 // Pointer types are allowed without explicit unsafe, they are just tokens
9220 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9221 typearg = QueriedType.ResolveAsType (ec, true);
9224 if (typearg == null)
9227 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9228 ec.Report.Error (1962, QueriedType.Location,
9229 "The typeof operator cannot be used on the dynamic type");
9233 type = ec.BuiltinTypes.Type;
9235 // Even though what is returned is a type object, it's treated as a value by the compiler.
9236 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9237 eclass = ExprClass.Value;
9241 static bool ContainsDynamicType (TypeSpec type)
9243 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9246 var element_container = type as ElementTypeSpec;
9247 if (element_container != null)
9248 return ContainsDynamicType (element_container.Element);
9250 foreach (var t in type.TypeArguments) {
9251 if (ContainsDynamicType (t)) {
9259 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9261 // Target type is not System.Type therefore must be object
9262 // and we need to use different encoding sequence
9263 if (targetType != type)
9266 if (typearg is InflatedTypeSpec) {
9269 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9270 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9271 typearg.GetSignatureForError ());
9275 gt = gt.DeclaringType;
9276 } while (gt != null);
9279 if (ContainsDynamicType (typearg)) {
9280 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9284 enc.EncodeTypeName (typearg);
9287 public override void Emit (EmitContext ec)
9289 ec.Emit (OpCodes.Ldtoken, typearg);
9290 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9292 ec.Emit (OpCodes.Call, m);
9295 public override object Accept (StructuralVisitor visitor)
9297 return visitor.Visit (this);
9301 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9303 public TypeOfMethod (MethodSpec method, Location loc)
9304 : base (method, loc)
9308 protected override Expression DoResolve (ResolveContext ec)
9310 if (member.IsConstructor) {
9311 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9313 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9319 return base.DoResolve (ec);
9322 public override void Emit (EmitContext ec)
9324 ec.Emit (OpCodes.Ldtoken, member);
9327 ec.Emit (OpCodes.Castclass, type);
9330 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9332 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9335 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9337 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9341 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9343 protected readonly T member;
9345 protected TypeOfMember (T member, Location loc)
9347 this.member = member;
9351 public override bool IsSideEffectFree {
9357 public override bool ContainsEmitWithAwait ()
9362 public override Expression CreateExpressionTree (ResolveContext ec)
9364 Arguments args = new Arguments (2);
9365 args.Add (new Argument (this));
9366 args.Add (new Argument (new TypeOf (type, loc)));
9367 return CreateExpressionFactoryCall (ec, "Constant", args);
9370 protected override Expression DoResolve (ResolveContext ec)
9372 eclass = ExprClass.Value;
9376 public override void Emit (EmitContext ec)
9378 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9379 PredefinedMember<MethodSpec> p;
9381 p = GetTypeFromHandleGeneric (ec);
9382 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9384 p = GetTypeFromHandle (ec);
9387 var mi = p.Resolve (loc);
9389 ec.Emit (OpCodes.Call, mi);
9392 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9393 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9396 sealed class TypeOfField : TypeOfMember<FieldSpec>
9398 public TypeOfField (FieldSpec field, Location loc)
9403 protected override Expression DoResolve (ResolveContext ec)
9405 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9409 return base.DoResolve (ec);
9412 public override void Emit (EmitContext ec)
9414 ec.Emit (OpCodes.Ldtoken, member);
9418 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9420 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9423 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9425 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9430 /// Implements the sizeof expression
9432 public class SizeOf : Expression {
9433 readonly Expression texpr;
9434 TypeSpec type_queried;
9436 public SizeOf (Expression queried_type, Location l)
9438 this.texpr = queried_type;
9442 public override bool IsSideEffectFree {
9448 public Expression TypeExpression {
9454 public override bool ContainsEmitWithAwait ()
9459 public override Expression CreateExpressionTree (ResolveContext ec)
9461 Error_PointerInsideExpressionTree (ec);
9465 protected override Expression DoResolve (ResolveContext ec)
9467 type_queried = texpr.ResolveAsType (ec);
9468 if (type_queried == null)
9471 if (type_queried.IsEnum)
9472 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9474 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9476 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9479 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9484 ec.Report.Error (233, loc,
9485 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9486 type_queried.GetSignatureForError ());
9489 type = ec.BuiltinTypes.Int;
9490 eclass = ExprClass.Value;
9494 public override void Emit (EmitContext ec)
9496 ec.Emit (OpCodes.Sizeof, type_queried);
9499 protected override void CloneTo (CloneContext clonectx, Expression t)
9503 public override object Accept (StructuralVisitor visitor)
9505 return visitor.Visit (this);
9510 /// Implements the qualified-alias-member (::) expression.
9512 public class QualifiedAliasMember : MemberAccess
9514 readonly string alias;
9515 public static readonly string GlobalAlias = "global";
9517 public QualifiedAliasMember (string alias, string identifier, Location l)
9518 : base (null, identifier, l)
9523 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9524 : base (null, identifier, targs, l)
9529 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9530 : base (null, identifier, arity, l)
9535 public string Alias {
9541 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9543 if (alias == GlobalAlias)
9544 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9546 int errors = mc.Module.Compiler.Report.Errors;
9547 var expr = mc.LookupNamespaceAlias (alias);
9549 if (errors == mc.Module.Compiler.Report.Errors)
9550 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9558 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9560 expr = CreateExpressionFromAlias (mc);
9564 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9567 protected override Expression DoResolve (ResolveContext rc)
9569 return ResolveAsTypeOrNamespace (rc, false);
9572 public override string GetSignatureForError ()
9575 if (targs != null) {
9576 name = Name + "<" + targs.GetSignatureForError () + ">";
9579 return alias + "::" + name;
9582 public override bool HasConditionalAccess ()
9587 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9589 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9590 rc.Module.Compiler.Report.Error (687, loc,
9591 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9592 GetSignatureForError ());
9597 return DoResolve (rc);
9600 protected override void CloneTo (CloneContext clonectx, Expression t)
9605 public override object Accept (StructuralVisitor visitor)
9607 return visitor.Visit (this);
9612 /// Implements the member access expression
9614 public class MemberAccess : ATypeNameExpression
9616 protected Expression expr;
9618 public MemberAccess (Expression expr, string id)
9619 : base (id, expr.Location)
9624 public MemberAccess (Expression expr, string identifier, Location loc)
9625 : base (identifier, loc)
9630 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9631 : base (identifier, args, loc)
9636 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9637 : base (identifier, arity, loc)
9642 public Expression LeftExpression {
9648 public override Location StartLocation {
9650 return expr == null ? loc : expr.StartLocation;
9654 protected override Expression DoResolve (ResolveContext rc)
9656 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9658 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9663 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9665 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9667 if (e is TypeExpr) {
9668 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9673 e = e.ResolveLValue (rc, rhs);
9678 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9680 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9681 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9683 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9686 public override bool HasConditionalAccess ()
9688 return LeftExpression.HasConditionalAccess ();
9691 public static bool IsValidDotExpression (TypeSpec type)
9693 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9694 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9696 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9699 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9701 var sn = expr as SimpleName;
9702 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9705 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9708 // Resolve expression which does have type set as we need expression type
9709 // with disable flow analysis as we don't know whether left side expression
9710 // is used as variable or type
9712 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9713 expr = expr.Resolve (rc);
9714 } else if (expr is TypeParameterExpr) {
9715 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9719 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9720 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9721 expr = expr.Resolve (rc, flags);
9724 expr = expr.Resolve (rc, flags);
9731 var ns = expr as NamespaceExpression;
9733 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9735 if (retval == null) {
9736 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9741 if (HasTypeArguments)
9742 return new GenericTypeExpr (retval.Type, targs, loc);
9744 targs.Resolve (rc, false);
9751 TypeSpec expr_type = expr.Type;
9752 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9753 me = expr as MemberExpr;
9755 me.ResolveInstanceExpression (rc, null);
9757 Arguments args = new Arguments (1);
9758 args.Add (new Argument (expr));
9759 return new DynamicMemberBinder (Name, args, loc);
9762 var cma = this as ConditionalMemberAccess;
9764 if (!IsNullPropagatingValid (expr.Type)) {
9765 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9769 if (expr_type.IsNullableType) {
9770 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9771 expr_type = expr.Type;
9775 if (!IsValidDotExpression (expr_type)) {
9776 Error_OperatorCannotBeApplied (rc, expr_type);
9780 var lookup_arity = Arity;
9781 bool errorMode = false;
9782 Expression member_lookup;
9784 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9785 if (member_lookup == null) {
9787 // Try to look for extension method when member lookup failed
9789 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9790 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9791 if (methods != null) {
9792 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9793 if (HasTypeArguments) {
9794 if (!targs.Resolve (rc, false))
9797 emg.SetTypeArguments (rc, targs);
9801 emg.ConditionalAccess = true;
9803 // TODO: it should really skip the checks bellow
9804 return emg.Resolve (rc);
9810 if (member_lookup == null) {
9811 var dep = expr_type.GetMissingDependencies ();
9813 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9814 } else if (expr is TypeExpr) {
9815 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9817 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9823 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9824 // Leave it to overload resolution to report correct error
9825 } else if (!(member_lookup is TypeExpr)) {
9826 // TODO: rc.SymbolRelatedToPreviousError
9827 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9832 if (member_lookup != null)
9836 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9840 TypeExpr texpr = member_lookup as TypeExpr;
9841 if (texpr != null) {
9842 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9843 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9844 Name, texpr.GetSignatureForError ());
9847 if (!texpr.Type.IsAccessible (rc)) {
9848 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9849 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9853 if (HasTypeArguments) {
9854 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9857 return member_lookup;
9860 me = member_lookup as MemberExpr;
9862 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9867 me.ConditionalAccess = true;
9870 me = me.ResolveMemberAccess (rc, expr, sn);
9873 if (!targs.Resolve (rc, false))
9876 me.SetTypeArguments (rc, targs);
9882 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9884 FullNamedExpression fexpr = expr as FullNamedExpression;
9885 if (fexpr == null) {
9886 expr.ResolveAsType (rc);
9890 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9892 if (expr_resolved == null)
9895 var ns = expr_resolved as NamespaceExpression;
9897 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9899 if (retval == null) {
9900 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9901 } else if (Arity > 0) {
9902 if (HasTypeArguments) {
9903 retval = new GenericTypeExpr (retval.Type, targs, loc);
9904 if (retval.ResolveAsType (rc) == null)
9907 targs.Resolve (rc, allowUnboundTypeArguments);
9909 retval = new GenericOpenTypeExpr (retval.Type, loc);
9916 var tnew_expr = expr_resolved.ResolveAsType (rc);
9917 if (tnew_expr == null)
9920 TypeSpec expr_type = tnew_expr;
9921 if (TypeManager.IsGenericParameter (expr_type)) {
9922 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9923 tnew_expr.GetSignatureForError ());
9927 var qam = this as QualifiedAliasMember;
9929 rc.Module.Compiler.Report.Error (431, loc,
9930 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9935 TypeSpec nested = null;
9936 while (expr_type != null) {
9937 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9938 if (nested == null) {
9939 if (expr_type == tnew_expr) {
9940 Error_IdentifierNotFound (rc, expr_type);
9944 expr_type = tnew_expr;
9945 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9946 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9950 if (nested.IsAccessible (rc))
9954 // Keep looking after inaccessible candidate but only if
9955 // we are not in same context as the definition itself
9957 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9960 expr_type = expr_type.BaseType;
9965 if (HasTypeArguments) {
9966 texpr = new GenericTypeExpr (nested, targs, loc);
9968 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9970 texpr = new GenericOpenTypeExpr (nested, loc);
9972 } else if (expr_resolved is GenericOpenTypeExpr) {
9973 texpr = new GenericOpenTypeExpr (nested, loc);
9975 texpr = new TypeExpression (nested, loc);
9978 if (texpr.ResolveAsType (rc) == null)
9984 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9986 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9988 if (nested != null) {
9989 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9993 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9994 if (any_other_member != null) {
9995 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9999 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10000 Name, expr_type.GetSignatureForError ());
10003 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10005 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10008 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10010 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10011 ec.Report.SymbolRelatedToPreviousError (type);
10013 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10015 // a using directive or an assembly reference
10016 if (cand != null) {
10017 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10019 missing = "an assembly reference";
10022 ec.Report.Error (1061, loc,
10023 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10024 type.GetSignatureForError (), name, missing);
10028 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10031 public override string GetSignatureForError ()
10033 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10036 protected override void CloneTo (CloneContext clonectx, Expression t)
10038 MemberAccess target = (MemberAccess) t;
10040 target.expr = expr.Clone (clonectx);
10043 public override object Accept (StructuralVisitor visitor)
10045 return visitor.Visit (this);
10049 public class ConditionalMemberAccess : MemberAccess
10051 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10052 : base (expr, identifier, args, loc)
10056 public override bool HasConditionalAccess ()
10063 /// Implements checked expressions
10065 public class CheckedExpr : Expression {
10067 public Expression Expr;
10069 public CheckedExpr (Expression e, Location l)
10075 public override bool ContainsEmitWithAwait ()
10077 return Expr.ContainsEmitWithAwait ();
10080 public override Expression CreateExpressionTree (ResolveContext ec)
10082 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10083 return Expr.CreateExpressionTree (ec);
10086 protected override Expression DoResolve (ResolveContext ec)
10088 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10089 Expr = Expr.Resolve (ec);
10094 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10097 eclass = Expr.eclass;
10102 public override void Emit (EmitContext ec)
10104 using (ec.With (EmitContext.Options.CheckedScope, true))
10108 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10110 using (ec.With (EmitContext.Options.CheckedScope, true))
10111 Expr.EmitBranchable (ec, target, on_true);
10114 public override void FlowAnalysis (FlowAnalysisContext fc)
10116 Expr.FlowAnalysis (fc);
10119 public override SLE.Expression MakeExpression (BuilderContext ctx)
10121 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10122 return Expr.MakeExpression (ctx);
10126 protected override void CloneTo (CloneContext clonectx, Expression t)
10128 CheckedExpr target = (CheckedExpr) t;
10130 target.Expr = Expr.Clone (clonectx);
10133 public override object Accept (StructuralVisitor visitor)
10135 return visitor.Visit (this);
10140 /// Implements the unchecked expression
10142 public class UnCheckedExpr : Expression {
10144 public Expression Expr;
10146 public UnCheckedExpr (Expression e, Location l)
10152 public override bool ContainsEmitWithAwait ()
10154 return Expr.ContainsEmitWithAwait ();
10157 public override Expression CreateExpressionTree (ResolveContext ec)
10159 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10160 return Expr.CreateExpressionTree (ec);
10163 protected override Expression DoResolve (ResolveContext ec)
10165 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10166 Expr = Expr.Resolve (ec);
10171 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10174 eclass = Expr.eclass;
10179 public override void Emit (EmitContext ec)
10181 using (ec.With (EmitContext.Options.CheckedScope, false))
10185 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10187 using (ec.With (EmitContext.Options.CheckedScope, false))
10188 Expr.EmitBranchable (ec, target, on_true);
10191 public override void FlowAnalysis (FlowAnalysisContext fc)
10193 Expr.FlowAnalysis (fc);
10196 protected override void CloneTo (CloneContext clonectx, Expression t)
10198 UnCheckedExpr target = (UnCheckedExpr) t;
10200 target.Expr = Expr.Clone (clonectx);
10203 public override object Accept (StructuralVisitor visitor)
10205 return visitor.Visit (this);
10210 /// An Element Access expression.
10212 /// During semantic analysis these are transformed into
10213 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10215 public class ElementAccess : Expression
10217 public Arguments Arguments;
10218 public Expression Expr;
10219 bool conditional_access_receiver;
10221 public ElementAccess (Expression e, Arguments args, Location loc)
10225 this.Arguments = args;
10228 public bool ConditionalAccess { get; set; }
10230 public override Location StartLocation {
10232 return Expr.StartLocation;
10236 public override bool ContainsEmitWithAwait ()
10238 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10242 // We perform some simple tests, and then to "split" the emit and store
10243 // code we create an instance of a different class, and return that.
10245 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10247 if (conditionalAccessReceiver)
10248 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10250 Expr = Expr.Resolve (ec);
10252 if (conditionalAccessReceiver)
10253 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10260 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10261 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10265 if (type.IsArray) {
10266 var aa = new ArrayAccess (this, loc) {
10267 ConditionalAccess = ConditionalAccess,
10270 if (conditionalAccessReceiver)
10271 aa.SetConditionalAccessReceiver ();
10276 if (type.IsPointer)
10277 return Expr.MakePointerAccess (ec, type, Arguments);
10279 FieldExpr fe = Expr as FieldExpr;
10281 var ff = fe.Spec as FixedFieldSpec;
10283 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10287 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10288 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10289 var indexer = new IndexerExpr (indexers, type, this) {
10290 ConditionalAccess = ConditionalAccess
10293 if (conditionalAccessReceiver)
10294 indexer.SetConditionalAccessReceiver ();
10299 Error_CannotApplyIndexing (ec, type, loc);
10304 public override Expression CreateExpressionTree (ResolveContext ec)
10306 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10307 Expr.CreateExpressionTree (ec));
10309 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10312 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10314 if (type != InternalType.ErrorType) {
10315 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10316 type.GetSignatureForError ());
10320 public override bool HasConditionalAccess ()
10322 return ConditionalAccess || Expr.HasConditionalAccess ();
10325 void ResolveConditionalAccessReceiver (ResolveContext rc)
10327 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10328 conditional_access_receiver = true;
10332 protected override Expression DoResolve (ResolveContext rc)
10334 ResolveConditionalAccessReceiver (rc);
10336 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10340 return expr.Resolve (rc);
10343 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10345 var res = CreateAccessExpression (ec, false);
10349 return res.ResolveLValue (ec, rhs);
10352 public override void Emit (EmitContext ec)
10354 throw new Exception ("Should never be reached");
10357 public override void FlowAnalysis (FlowAnalysisContext fc)
10359 Expr.FlowAnalysis (fc);
10361 Arguments.FlowAnalysis (fc);
10364 public override string GetSignatureForError ()
10366 return Expr.GetSignatureForError ();
10369 protected override void CloneTo (CloneContext clonectx, Expression t)
10371 ElementAccess target = (ElementAccess) t;
10373 target.Expr = Expr.Clone (clonectx);
10374 if (Arguments != null)
10375 target.Arguments = Arguments.Clone (clonectx);
10378 public override object Accept (StructuralVisitor visitor)
10380 return visitor.Visit (this);
10385 /// Implements array access
10387 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10389 // Points to our "data" repository
10393 LocalTemporary temp;
10395 bool? has_await_args;
10396 bool conditional_access_receiver;
10398 public ArrayAccess (ElementAccess ea_data, Location l)
10404 public bool ConditionalAccess { get; set; }
10406 public void AddressOf (EmitContext ec, AddressOp mode)
10408 var ac = (ArrayContainer) ea.Expr.Type;
10410 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10411 LoadInstanceAndArguments (ec, false, true);
10414 LoadInstanceAndArguments (ec, false, false);
10416 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10417 ec.Emit (OpCodes.Readonly);
10419 ec.EmitArrayAddress (ac);
10422 public override Expression CreateExpressionTree (ResolveContext ec)
10424 if (ConditionalAccess)
10425 Error_NullShortCircuitInsideExpressionTree (ec);
10427 return ea.CreateExpressionTree (ec);
10430 public override bool ContainsEmitWithAwait ()
10432 return ea.ContainsEmitWithAwait ();
10435 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10437 if (HasConditionalAccess ())
10438 Error_NullPropagatingLValue (ec);
10440 return DoResolve (ec);
10443 protected override Expression DoResolve (ResolveContext ec)
10445 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10447 ea.Arguments.Resolve (ec, out dynamic);
10449 var ac = ea.Expr.Type as ArrayContainer;
10450 int rank = ea.Arguments.Count;
10451 if (ac.Rank != rank) {
10452 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10453 rank.ToString (), ac.Rank.ToString ());
10458 if (type.IsPointer && !ec.IsUnsafe) {
10459 UnsafeError (ec, ea.Location);
10462 if (conditional_access_receiver)
10463 type = LiftMemberType (ec, type);
10465 foreach (Argument a in ea.Arguments) {
10466 var na = a as NamedArgument;
10468 ElementAccess.Error_NamedArgument (na, ec.Report);
10470 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10473 eclass = ExprClass.Variable;
10478 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10480 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10483 public override void FlowAnalysis (FlowAnalysisContext fc)
10485 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10487 ea.FlowAnalysis (fc);
10489 if (conditional_access_receiver)
10490 fc.DefiniteAssignment = da;
10493 public override bool HasConditionalAccess ()
10495 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10499 // Load the array arguments into the stack.
10501 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10503 if (prepareAwait) {
10504 ea.Expr = ea.Expr.EmitToField (ec);
10506 var ie = new InstanceEmitter (ea.Expr, false);
10507 ie.Emit (ec, ConditionalAccess);
10509 if (duplicateArguments) {
10510 ec.Emit (OpCodes.Dup);
10512 var copy = new LocalTemporary (ea.Expr.Type);
10518 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10519 if (dup_args != null)
10520 ea.Arguments = dup_args;
10523 public void Emit (EmitContext ec, bool leave_copy)
10526 ec.EmitLoadFromPtr (type);
10528 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10529 LoadInstanceAndArguments (ec, false, true);
10532 if (conditional_access_receiver)
10533 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10535 var ac = (ArrayContainer) ea.Expr.Type;
10536 LoadInstanceAndArguments (ec, false, false);
10537 ec.EmitArrayLoad (ac);
10539 if (conditional_access_receiver)
10540 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10544 ec.Emit (OpCodes.Dup);
10545 temp = new LocalTemporary (this.type);
10550 public override void Emit (EmitContext ec)
10555 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10557 var ac = (ArrayContainer) ea.Expr.Type;
10558 TypeSpec t = source.Type;
10560 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10563 // When we are dealing with a struct, get the address of it to avoid value copy
10564 // Same cannot be done for reference type because array covariance and the
10565 // check in ldelema requires to specify the type of array element stored at the index
10567 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10568 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10570 if (has_await_args.Value) {
10571 if (source.ContainsEmitWithAwait ()) {
10572 source = source.EmitToField (ec);
10573 isCompound = false;
10577 LoadInstanceAndArguments (ec, isCompound, false);
10582 ec.EmitArrayAddress (ac);
10585 ec.Emit (OpCodes.Dup);
10589 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10591 if (has_await_args.Value) {
10592 if (source.ContainsEmitWithAwait ())
10593 source = source.EmitToField (ec);
10595 LoadInstanceAndArguments (ec, false, false);
10602 var lt = ea.Expr as LocalTemporary;
10608 ec.Emit (OpCodes.Dup);
10609 temp = new LocalTemporary (this.type);
10614 ec.EmitStoreFromPtr (t);
10616 ec.EmitArrayStore (ac);
10619 if (temp != null) {
10625 public override Expression EmitToField (EmitContext ec)
10628 // Have to be specialized for arrays to get access to
10629 // underlying element. Instead of another result copy we
10630 // need direct access to element
10634 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10636 ea.Expr = ea.Expr.EmitToField (ec);
10637 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10641 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10643 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10646 public override SLE.Expression MakeExpression (BuilderContext ctx)
10648 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10651 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10653 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10654 return Arguments.MakeExpression (ea.Arguments, ctx);
10658 public void SetConditionalAccessReceiver ()
10660 conditional_access_receiver = true;
10665 // Indexer access expression
10667 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10669 IList<MemberSpec> indexers;
10670 Arguments arguments;
10671 TypeSpec queried_type;
10673 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10674 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10678 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10681 this.indexers = indexers;
10682 this.queried_type = queriedType;
10683 this.InstanceExpression = instance;
10684 this.arguments = args;
10689 protected override Arguments Arguments {
10698 protected override TypeSpec DeclaringType {
10700 return best_candidate.DeclaringType;
10704 public override bool IsInstance {
10710 public override bool IsStatic {
10716 public override string KindName {
10717 get { return "indexer"; }
10720 public override string Name {
10728 public override bool ContainsEmitWithAwait ()
10730 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10733 public override Expression CreateExpressionTree (ResolveContext ec)
10735 if (ConditionalAccess) {
10736 Error_NullShortCircuitInsideExpressionTree (ec);
10739 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10740 InstanceExpression.CreateExpressionTree (ec),
10741 new TypeOfMethod (Getter, loc));
10743 return CreateExpressionFactoryCall (ec, "Call", args);
10746 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10748 LocalTemporary await_source_arg = null;
10751 emitting_compound_assignment = true;
10752 if (source is DynamicExpressionStatement) {
10757 emitting_compound_assignment = false;
10759 if (has_await_arguments) {
10760 await_source_arg = new LocalTemporary (Type);
10761 await_source_arg.Store (ec);
10763 arguments.Add (new Argument (await_source_arg));
10766 temp = await_source_arg;
10769 has_await_arguments = false;
10774 ec.Emit (OpCodes.Dup);
10775 temp = new LocalTemporary (Type);
10781 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10782 source = source.EmitToField (ec);
10784 temp = new LocalTemporary (Type);
10791 arguments.Add (new Argument (source));
10794 var call = new CallEmitter ();
10795 call.InstanceExpression = InstanceExpression;
10796 if (arguments == null)
10797 call.InstanceExpressionOnStack = true;
10799 call.Emit (ec, Setter, arguments, loc);
10801 if (temp != null) {
10804 } else if (leave_copy) {
10808 if (await_source_arg != null) {
10809 await_source_arg.Release (ec);
10813 public override void FlowAnalysis (FlowAnalysisContext fc)
10815 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10817 base.FlowAnalysis (fc);
10818 arguments.FlowAnalysis (fc);
10820 if (conditional_access_receiver)
10821 fc.DefiniteAssignment = da;
10824 public override string GetSignatureForError ()
10826 return best_candidate.GetSignatureForError ();
10829 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10832 throw new NotSupportedException ();
10834 var value = new[] { source.MakeExpression (ctx) };
10835 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10836 return SLE.Expression.Block (
10837 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10842 public override SLE.Expression MakeExpression (BuilderContext ctx)
10845 return base.MakeExpression (ctx);
10847 var args = Arguments.MakeExpression (arguments, ctx);
10848 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10852 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10854 if (best_candidate != null)
10857 eclass = ExprClass.IndexerAccess;
10860 arguments.Resolve (rc, out dynamic);
10862 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10865 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10866 res.BaseMembersProvider = this;
10867 res.InstanceQualifier = this;
10869 // TODO: Do I need 2 argument sets?
10870 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10871 if (best_candidate != null)
10872 type = res.BestCandidateReturnType;
10873 else if (!res.BestCandidateIsDynamic)
10878 // It has dynamic arguments
10881 Arguments args = new Arguments (arguments.Count + 1);
10883 rc.Report.Error (1972, loc,
10884 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10886 args.Add (new Argument (InstanceExpression));
10888 args.AddRange (arguments);
10890 best_candidate = null;
10891 return new DynamicIndexBinder (args, loc);
10895 // Try to avoid resolving left expression again
10897 if (right_side != null)
10898 ResolveInstanceExpression (rc, right_side);
10903 protected override void CloneTo (CloneContext clonectx, Expression t)
10905 IndexerExpr target = (IndexerExpr) t;
10907 if (arguments != null)
10908 target.arguments = arguments.Clone (clonectx);
10911 public void SetConditionalAccessReceiver ()
10913 conditional_access_receiver = true;
10916 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10918 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10921 #region IBaseMembersProvider Members
10923 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10925 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10928 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10930 if (queried_type == member.DeclaringType)
10933 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10934 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10937 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10946 // A base access expression
10948 public class BaseThis : This
10950 public BaseThis (Location loc)
10955 public BaseThis (TypeSpec type, Location loc)
10959 eclass = ExprClass.Variable;
10964 public override string Name {
10972 public override Expression CreateExpressionTree (ResolveContext ec)
10974 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10975 return base.CreateExpressionTree (ec);
10978 public override void Emit (EmitContext ec)
10982 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10983 var context_type = ec.CurrentType;
10984 ec.Emit (OpCodes.Ldobj, context_type);
10985 ec.Emit (OpCodes.Box, context_type);
10989 protected override void Error_ThisNotAvailable (ResolveContext ec)
10992 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10994 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10998 public override void ResolveBase (ResolveContext ec)
11000 base.ResolveBase (ec);
11001 type = ec.CurrentType.BaseType;
11004 public override object Accept (StructuralVisitor visitor)
11006 return visitor.Visit (this);
11011 /// This class exists solely to pass the Type around and to be a dummy
11012 /// that can be passed to the conversion functions (this is used by
11013 /// foreach implementation to typecast the object return value from
11014 /// get_Current into the proper type. All code has been generated and
11015 /// we only care about the side effect conversions to be performed
11017 /// This is also now used as a placeholder where a no-action expression
11018 /// is needed (the `New' class).
11020 public class EmptyExpression : Expression
11022 sealed class OutAccessExpression : EmptyExpression
11024 public OutAccessExpression (TypeSpec t)
11029 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11031 rc.Report.Error (206, right_side.Location,
11032 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11038 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11039 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11040 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11041 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11042 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11043 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11044 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11045 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11047 public EmptyExpression (TypeSpec t)
11050 eclass = ExprClass.Value;
11051 loc = Location.Null;
11054 protected override void CloneTo (CloneContext clonectx, Expression target)
11058 public override bool ContainsEmitWithAwait ()
11063 public override Expression CreateExpressionTree (ResolveContext ec)
11065 throw new NotSupportedException ("ET");
11068 protected override Expression DoResolve (ResolveContext ec)
11073 public override void Emit (EmitContext ec)
11075 // nothing, as we only exist to not do anything.
11078 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11082 public override void EmitSideEffect (EmitContext ec)
11086 public override object Accept (StructuralVisitor visitor)
11088 return visitor.Visit (this);
11092 sealed class EmptyAwaitExpression : EmptyExpression
11094 public EmptyAwaitExpression (TypeSpec type)
11099 public override bool ContainsEmitWithAwait ()
11106 // Empty statement expression
11108 public sealed class EmptyExpressionStatement : ExpressionStatement
11110 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11112 private EmptyExpressionStatement ()
11114 loc = Location.Null;
11117 public override bool ContainsEmitWithAwait ()
11122 public override Expression CreateExpressionTree (ResolveContext ec)
11127 public override void EmitStatement (EmitContext ec)
11132 protected override Expression DoResolve (ResolveContext ec)
11134 eclass = ExprClass.Value;
11135 type = ec.BuiltinTypes.Object;
11139 public override void Emit (EmitContext ec)
11144 public override object Accept (StructuralVisitor visitor)
11146 return visitor.Visit (this);
11150 public class ErrorExpression : EmptyExpression
11152 public static readonly ErrorExpression Instance = new ErrorExpression ();
11154 private ErrorExpression ()
11155 : base (InternalType.ErrorType)
11159 public override Expression CreateExpressionTree (ResolveContext ec)
11164 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11169 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11173 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11177 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11181 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11185 public override object Accept (StructuralVisitor visitor)
11187 return visitor.Visit (this);
11191 public class UserCast : Expression {
11195 public UserCast (MethodSpec method, Expression source, Location l)
11197 if (source == null)
11198 throw new ArgumentNullException ("source");
11200 this.method = method;
11201 this.source = source;
11202 type = method.ReturnType;
11206 public Expression Source {
11215 public override bool ContainsEmitWithAwait ()
11217 return source.ContainsEmitWithAwait ();
11220 public override Expression CreateExpressionTree (ResolveContext ec)
11222 Arguments args = new Arguments (3);
11223 args.Add (new Argument (source.CreateExpressionTree (ec)));
11224 args.Add (new Argument (new TypeOf (type, loc)));
11225 args.Add (new Argument (new TypeOfMethod (method, loc)));
11226 return CreateExpressionFactoryCall (ec, "Convert", args);
11229 protected override Expression DoResolve (ResolveContext ec)
11231 method.CheckObsoleteness (ec, source.Location);
11233 eclass = ExprClass.Value;
11237 public override void Emit (EmitContext ec)
11240 ec.MarkCallEntry (loc);
11241 ec.Emit (OpCodes.Call, method);
11244 public override void FlowAnalysis (FlowAnalysisContext fc)
11246 source.FlowAnalysis (fc);
11249 public override string GetSignatureForError ()
11251 return TypeManager.CSharpSignature (method);
11254 public override SLE.Expression MakeExpression (BuilderContext ctx)
11257 return base.MakeExpression (ctx);
11259 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11265 // Holds additional type specifiers like ?, *, []
11267 public class ComposedTypeSpecifier
11269 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11271 public readonly int Dimension;
11272 public readonly Location Location;
11274 public ComposedTypeSpecifier (int specifier, Location loc)
11276 this.Dimension = specifier;
11277 this.Location = loc;
11281 public bool IsNullable {
11283 return Dimension == -1;
11287 public bool IsPointer {
11289 return Dimension == -2;
11293 public ComposedTypeSpecifier Next { get; set; }
11297 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11299 return new ComposedTypeSpecifier (dimension, loc);
11302 public static ComposedTypeSpecifier CreateNullable (Location loc)
11304 return new ComposedTypeSpecifier (-1, loc);
11307 public static ComposedTypeSpecifier CreatePointer (Location loc)
11309 return new ComposedTypeSpecifier (-2, loc);
11312 public string GetSignatureForError ()
11317 ArrayContainer.GetPostfixSignature (Dimension);
11319 return Next != null ? s + Next.GetSignatureForError () : s;
11324 // This class is used to "construct" the type during a typecast
11325 // operation. Since the Type.GetType class in .NET can parse
11326 // the type specification, we just use this to construct the type
11327 // one bit at a time.
11329 public class ComposedCast : TypeExpr {
11330 FullNamedExpression left;
11331 ComposedTypeSpecifier spec;
11333 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11336 throw new ArgumentNullException ("spec");
11340 this.loc = left.Location;
11343 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11345 type = left.ResolveAsType (ec);
11349 eclass = ExprClass.Type;
11351 var single_spec = spec;
11353 if (single_spec.IsNullable) {
11354 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11358 single_spec = single_spec.Next;
11359 } else if (single_spec.IsPointer) {
11361 // Declared fields cannot have unmanaged check done before all types are defined
11363 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11366 if (!ec.IsUnsafe) {
11367 UnsafeError (ec.Module.Compiler.Report, loc);
11371 type = PointerContainer.MakeType (ec.Module, type);
11372 single_spec = single_spec.Next;
11373 } while (single_spec != null && single_spec.IsPointer);
11376 if (single_spec != null && single_spec.Dimension > 0) {
11377 if (type.IsSpecialRuntimeType) {
11378 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11379 } else if (type.IsStatic) {
11380 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11381 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11382 type.GetSignatureForError ());
11384 MakeArray (ec.Module, single_spec);
11391 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11393 if (spec.Next != null)
11394 MakeArray (module, spec.Next);
11396 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11399 public override string GetSignatureForError ()
11401 return left.GetSignatureForError () + spec.GetSignatureForError ();
11404 public override object Accept (StructuralVisitor visitor)
11406 return visitor.Visit (this);
11410 class FixedBufferPtr : Expression
11412 readonly Expression array;
11414 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11416 this.type = array_type;
11417 this.array = array;
11421 public override bool ContainsEmitWithAwait ()
11423 throw new NotImplementedException ();
11426 public override Expression CreateExpressionTree (ResolveContext ec)
11428 Error_PointerInsideExpressionTree (ec);
11432 public override void Emit(EmitContext ec)
11437 protected override Expression DoResolve (ResolveContext ec)
11439 type = PointerContainer.MakeType (ec.Module, type);
11440 eclass = ExprClass.Value;
11447 // This class is used to represent the address of an array, used
11448 // only by the Fixed statement, this generates "&a [0]" construct
11449 // for fixed (char *pa = a)
11451 class ArrayPtr : FixedBufferPtr
11453 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11454 base (array, array_type, l)
11458 public override void Emit (EmitContext ec)
11463 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11468 // Encapsulates a conversion rules required for array indexes
11470 public class ArrayIndexCast : TypeCast
11472 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11473 : base (expr, returnType)
11475 if (expr.Type == returnType) // int -> int
11476 throw new ArgumentException ("unnecessary array index conversion");
11479 public override Expression CreateExpressionTree (ResolveContext ec)
11481 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11482 return base.CreateExpressionTree (ec);
11486 public override void Emit (EmitContext ec)
11490 switch (child.Type.BuiltinType) {
11491 case BuiltinTypeSpec.Type.UInt:
11492 ec.Emit (OpCodes.Conv_U);
11494 case BuiltinTypeSpec.Type.Long:
11495 ec.Emit (OpCodes.Conv_Ovf_I);
11497 case BuiltinTypeSpec.Type.ULong:
11498 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11501 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11507 // Implements the `stackalloc' keyword
11509 public class StackAlloc : Expression {
11514 public StackAlloc (Expression type, Expression count, Location l)
11517 this.count = count;
11521 public Expression TypeExpression {
11527 public Expression CountExpression {
11533 public override bool ContainsEmitWithAwait ()
11538 public override Expression CreateExpressionTree (ResolveContext ec)
11540 throw new NotSupportedException ("ET");
11543 protected override Expression DoResolve (ResolveContext ec)
11545 count = count.Resolve (ec);
11549 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11550 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11555 Constant c = count as Constant;
11556 if (c != null && c.IsNegative) {
11557 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11560 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11561 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11564 otype = texpr.ResolveAsType (ec);
11568 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11571 type = PointerContainer.MakeType (ec.Module, otype);
11572 eclass = ExprClass.Value;
11577 public override void Emit (EmitContext ec)
11579 int size = BuiltinTypeSpec.GetSize (otype);
11584 ec.Emit (OpCodes.Sizeof, otype);
11588 ec.Emit (OpCodes.Mul_Ovf_Un);
11589 ec.Emit (OpCodes.Localloc);
11592 protected override void CloneTo (CloneContext clonectx, Expression t)
11594 StackAlloc target = (StackAlloc) t;
11595 target.count = count.Clone (clonectx);
11596 target.texpr = texpr.Clone (clonectx);
11599 public override object Accept (StructuralVisitor visitor)
11601 return visitor.Visit (this);
11606 // An object initializer expression
11608 public class ElementInitializer : Assign
11610 public readonly string Name;
11612 public ElementInitializer (string name, Expression initializer, Location loc)
11613 : base (null, initializer, loc)
11618 public bool IsDictionaryInitializer {
11620 return Name == null;
11624 protected override void CloneTo (CloneContext clonectx, Expression t)
11626 ElementInitializer target = (ElementInitializer) t;
11627 target.source = source.Clone (clonectx);
11630 public override Expression CreateExpressionTree (ResolveContext ec)
11632 Arguments args = new Arguments (2);
11633 FieldExpr fe = target as FieldExpr;
11635 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11637 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11640 Expression arg_expr;
11641 var cinit = source as CollectionOrObjectInitializers;
11642 if (cinit == null) {
11644 arg_expr = source.CreateExpressionTree (ec);
11646 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11647 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11650 args.Add (new Argument (arg_expr));
11651 return CreateExpressionFactoryCall (ec, mname, args);
11654 protected override Expression DoResolve (ResolveContext ec)
11656 if (source == null)
11657 return EmptyExpressionStatement.Instance;
11659 if (!ResolveElement (ec))
11662 if (source is CollectionOrObjectInitializers) {
11663 target = target.Resolve (ec);
11664 if (target == null)
11667 Expression previous = ec.CurrentInitializerVariable;
11668 ec.CurrentInitializerVariable = target;
11669 source = source.Resolve (ec);
11670 ec.CurrentInitializerVariable = previous;
11671 if (source == null)
11674 eclass = source.eclass;
11675 type = source.Type;
11680 return base.DoResolve (ec);
11683 public override void EmitStatement (EmitContext ec)
11685 if (source is CollectionOrObjectInitializers)
11688 base.EmitStatement (ec);
11691 protected virtual bool ResolveElement (ResolveContext rc)
11693 var t = rc.CurrentInitializerVariable.Type;
11694 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11695 Arguments args = new Arguments (1);
11696 args.Add (new Argument (rc.CurrentInitializerVariable));
11697 target = new DynamicMemberBinder (Name, args, loc);
11700 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11701 if (member == null) {
11702 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11704 if (member != null) {
11705 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11706 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11711 if (member == null) {
11712 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11716 var me = member as MemberExpr;
11717 if (me is EventExpr) {
11718 me = me.ResolveMemberAccess (rc, null, null);
11719 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11720 rc.Report.Error (1913, loc,
11721 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11722 member.GetSignatureForError ());
11728 rc.Report.Error (1914, loc,
11729 "Static field or property `{0}' cannot be assigned in an object initializer",
11730 me.GetSignatureForError ());
11734 me.InstanceExpression = rc.CurrentInitializerVariable;
11742 // A collection initializer expression
11744 class CollectionElementInitializer : Invocation
11746 public class ElementInitializerArgument : Argument
11748 public ElementInitializerArgument (Expression e)
11754 sealed class AddMemberAccess : MemberAccess
11756 public AddMemberAccess (Expression expr, Location loc)
11757 : base (expr, "Add", loc)
11761 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11763 if (TypeManager.HasElementType (type))
11766 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11770 public CollectionElementInitializer (Expression argument)
11771 : base (null, new Arguments (1))
11773 base.arguments.Add (new ElementInitializerArgument (argument));
11774 this.loc = argument.Location;
11777 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11778 : base (null, new Arguments (arguments.Count))
11780 foreach (Expression e in arguments)
11781 base.arguments.Add (new ElementInitializerArgument (e));
11786 public CollectionElementInitializer (Location loc)
11787 : base (null, null)
11792 public override Expression CreateExpressionTree (ResolveContext ec)
11794 Arguments args = new Arguments (2);
11795 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11797 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11798 foreach (Argument a in arguments) {
11799 if (a.ArgType == Argument.AType.ExtensionType) {
11800 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11803 expr_initializers.Add (a.CreateExpressionTree (ec));
11806 args.Add (new Argument (new ArrayCreation (
11807 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11808 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11811 protected override void CloneTo (CloneContext clonectx, Expression t)
11813 CollectionElementInitializer target = (CollectionElementInitializer) t;
11814 if (arguments != null)
11815 target.arguments = arguments.Clone (clonectx);
11818 protected override Expression DoResolve (ResolveContext ec)
11820 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11822 return base.DoResolve (ec);
11826 class DictionaryElementInitializer : ElementInitializer
11828 readonly Arguments args;
11830 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11831 : base (null, initializer, loc)
11833 this.args = arguments;
11836 public override Expression CreateExpressionTree (ResolveContext ec)
11838 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11842 protected override bool ResolveElement (ResolveContext rc)
11844 var init = rc.CurrentInitializerVariable;
11845 var type = init.Type;
11847 if (type.IsArray) {
11848 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11852 if (type.IsPointer) {
11853 target = init.MakePointerAccess (rc, type, args);
11857 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11858 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11859 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11863 target = new IndexerExpr (indexers, type, init, args, loc);
11869 // A block of object or collection initializers
11871 public class CollectionOrObjectInitializers : ExpressionStatement
11873 IList<Expression> initializers;
11874 bool is_collection_initialization;
11876 public CollectionOrObjectInitializers (Location loc)
11877 : this (new Expression[0], loc)
11881 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11883 this.initializers = initializers;
11887 public IList<Expression> Initializers {
11889 return initializers;
11893 public bool IsEmpty {
11895 return initializers.Count == 0;
11899 public bool IsCollectionInitializer {
11901 return is_collection_initialization;
11905 protected override void CloneTo (CloneContext clonectx, Expression target)
11907 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11909 t.initializers = new List<Expression> (initializers.Count);
11910 foreach (var e in initializers)
11911 t.initializers.Add (e.Clone (clonectx));
11914 public override bool ContainsEmitWithAwait ()
11916 foreach (var e in initializers) {
11917 if (e.ContainsEmitWithAwait ())
11924 public override Expression CreateExpressionTree (ResolveContext ec)
11926 return CreateExpressionTree (ec, false);
11929 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11931 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11932 foreach (Expression e in initializers) {
11933 Expression expr = e.CreateExpressionTree (ec);
11935 expr_initializers.Add (expr);
11939 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11941 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11944 protected override Expression DoResolve (ResolveContext ec)
11946 List<string> element_names = null;
11947 for (int i = 0; i < initializers.Count; ++i) {
11948 Expression initializer = initializers [i];
11949 ElementInitializer element_initializer = initializer as ElementInitializer;
11952 if (element_initializer != null) {
11953 element_names = new List<string> (initializers.Count);
11954 if (!element_initializer.IsDictionaryInitializer)
11955 element_names.Add (element_initializer.Name);
11956 } else if (initializer is CompletingExpression) {
11957 initializer.Resolve (ec);
11958 throw new InternalErrorException ("This line should never be reached");
11960 var t = ec.CurrentInitializerVariable.Type;
11961 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11962 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11963 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11964 "object initializer because type `{1}' does not implement `{2}' interface",
11965 ec.CurrentInitializerVariable.GetSignatureForError (),
11966 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11967 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11970 is_collection_initialization = true;
11973 if (is_collection_initialization != (element_initializer == null)) {
11974 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11975 is_collection_initialization ? "collection initializer" : "object initializer");
11979 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11980 if (element_names.Contains (element_initializer.Name)) {
11981 ec.Report.Error (1912, element_initializer.Location,
11982 "An object initializer includes more than one member `{0}' initialization",
11983 element_initializer.Name);
11985 element_names.Add (element_initializer.Name);
11990 Expression e = initializer.Resolve (ec);
11991 if (e == EmptyExpressionStatement.Instance)
11992 initializers.RemoveAt (i--);
11994 initializers [i] = e;
11997 type = ec.CurrentInitializerVariable.Type;
11998 if (is_collection_initialization) {
11999 if (TypeManager.HasElementType (type)) {
12000 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12001 type.GetSignatureForError ());
12005 eclass = ExprClass.Variable;
12009 public override void Emit (EmitContext ec)
12011 EmitStatement (ec);
12014 public override void EmitStatement (EmitContext ec)
12016 foreach (ExpressionStatement e in initializers) {
12017 // TODO: need location region
12018 ec.Mark (e.Location);
12019 e.EmitStatement (ec);
12023 public override void FlowAnalysis (FlowAnalysisContext fc)
12025 foreach (var initializer in initializers) {
12026 if (initializer != null)
12027 initializer.FlowAnalysis (fc);
12033 // New expression with element/object initializers
12035 public class NewInitialize : New
12038 // This class serves as a proxy for variable initializer target instances.
12039 // A real variable is assigned later when we resolve left side of an
12042 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12044 NewInitialize new_instance;
12046 public InitializerTargetExpression (NewInitialize newInstance)
12048 this.type = newInstance.type;
12049 this.loc = newInstance.loc;
12050 this.eclass = newInstance.eclass;
12051 this.new_instance = newInstance;
12054 public override bool ContainsEmitWithAwait ()
12059 public override Expression CreateExpressionTree (ResolveContext ec)
12061 // Should not be reached
12062 throw new NotSupportedException ("ET");
12065 protected override Expression DoResolve (ResolveContext ec)
12070 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12075 public override void Emit (EmitContext ec)
12077 Expression e = (Expression) new_instance.instance;
12081 public override Expression EmitToField (EmitContext ec)
12083 return (Expression) new_instance.instance;
12086 #region IMemoryLocation Members
12088 public void AddressOf (EmitContext ec, AddressOp mode)
12090 new_instance.instance.AddressOf (ec, mode);
12096 CollectionOrObjectInitializers initializers;
12097 IMemoryLocation instance;
12098 DynamicExpressionStatement dynamic;
12100 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12101 : base (requested_type, arguments, l)
12103 this.initializers = initializers;
12106 public CollectionOrObjectInitializers Initializers {
12108 return initializers;
12112 protected override void CloneTo (CloneContext clonectx, Expression t)
12114 base.CloneTo (clonectx, t);
12116 NewInitialize target = (NewInitialize) t;
12117 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12120 public override bool ContainsEmitWithAwait ()
12122 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12125 public override Expression CreateExpressionTree (ResolveContext ec)
12127 Arguments args = new Arguments (2);
12128 args.Add (new Argument (base.CreateExpressionTree (ec)));
12129 if (!initializers.IsEmpty)
12130 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12132 return CreateExpressionFactoryCall (ec,
12133 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12137 protected override Expression DoResolve (ResolveContext ec)
12139 Expression e = base.DoResolve (ec);
12143 if (type.IsDelegate) {
12144 ec.Report.Error (1958, Initializers.Location,
12145 "Object and collection initializers cannot be used to instantiate a delegate");
12148 Expression previous = ec.CurrentInitializerVariable;
12149 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12150 initializers.Resolve (ec);
12151 ec.CurrentInitializerVariable = previous;
12153 dynamic = e as DynamicExpressionStatement;
12154 if (dynamic != null)
12160 public override void Emit (EmitContext ec)
12162 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12163 var fe = ec.GetTemporaryField (type);
12165 if (!Emit (ec, fe))
12174 public override bool Emit (EmitContext ec, IMemoryLocation target)
12177 // Expression is initialized into temporary target then moved
12178 // to real one for atomicity
12180 IMemoryLocation temp_target = target;
12182 LocalTemporary temp = null;
12183 bool by_ref = false;
12184 if (!initializers.IsEmpty) {
12185 temp_target = target as LocalTemporary;
12186 if (temp_target == null)
12187 temp_target = target as StackFieldExpr;
12189 if (temp_target == null) {
12190 var vr = target as VariableReference;
12191 if (vr != null && vr.IsRef) {
12197 if (temp_target == null)
12198 temp_target = temp = new LocalTemporary (type);
12201 bool left_on_stack;
12202 if (dynamic != null) {
12204 left_on_stack = true;
12206 left_on_stack = base.Emit (ec, temp_target);
12209 if (initializers.IsEmpty)
12210 return left_on_stack;
12212 StackFieldExpr sf = null;
12214 // Move a new instance (reference-type) to local temporary variable
12215 if (left_on_stack) {
12217 temp_target = temp = new LocalTemporary (type);
12223 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12225 throw new NotImplementedException ();
12227 sf = ec.GetTemporaryField (type);
12228 sf.EmitAssign (ec, temp, false, false);
12231 left_on_stack = false;
12235 instance = temp_target;
12237 initializers.Emit (ec);
12239 ((Expression)temp_target).Emit (ec);
12245 sf.IsAvailableForReuse = true;
12250 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12252 instance = base.EmitAddressOf (ec, Mode);
12254 if (!initializers.IsEmpty)
12255 initializers.Emit (ec);
12260 public override void FlowAnalysis (FlowAnalysisContext fc)
12262 base.FlowAnalysis (fc);
12263 initializers.FlowAnalysis (fc);
12266 public override object Accept (StructuralVisitor visitor)
12268 return visitor.Visit (this);
12272 public class NewAnonymousType : New
12274 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12276 List<AnonymousTypeParameter> parameters;
12277 readonly TypeContainer parent;
12278 AnonymousTypeClass anonymous_type;
12280 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12281 : base (null, null, loc)
12283 this.parameters = parameters;
12284 this.parent = parent;
12287 public List<AnonymousTypeParameter> Parameters {
12289 return this.parameters;
12293 protected override void CloneTo (CloneContext clonectx, Expression target)
12295 if (parameters == null)
12298 NewAnonymousType t = (NewAnonymousType) target;
12299 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12300 foreach (AnonymousTypeParameter atp in parameters)
12301 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12304 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12306 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12310 type = AnonymousTypeClass.Create (parent, parameters, loc);
12314 int errors = ec.Report.Errors;
12315 type.CreateContainer ();
12316 type.DefineContainer ();
12318 if ((ec.Report.Errors - errors) == 0) {
12319 parent.Module.AddAnonymousType (type);
12320 type.PrepareEmit ();
12326 public override Expression CreateExpressionTree (ResolveContext ec)
12328 if (parameters == null)
12329 return base.CreateExpressionTree (ec);
12331 var init = new ArrayInitializer (parameters.Count, loc);
12332 foreach (var m in anonymous_type.Members) {
12333 var p = m as Property;
12335 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12338 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12339 foreach (Argument a in arguments)
12340 ctor_args.Add (a.CreateExpressionTree (ec));
12342 Arguments args = new Arguments (3);
12343 args.Add (new Argument (new TypeOfMethod (method, loc)));
12344 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12345 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12347 return CreateExpressionFactoryCall (ec, "New", args);
12350 protected override Expression DoResolve (ResolveContext ec)
12352 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12353 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12357 if (parameters == null) {
12358 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12359 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12360 return base.DoResolve (ec);
12363 bool error = false;
12364 arguments = new Arguments (parameters.Count);
12365 var t_args = new TypeSpec [parameters.Count];
12366 for (int i = 0; i < parameters.Count; ++i) {
12367 Expression e = parameters [i].Resolve (ec);
12373 arguments.Add (new Argument (e));
12374 t_args [i] = e.Type;
12380 anonymous_type = CreateAnonymousType (ec, parameters);
12381 if (anonymous_type == null)
12384 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12385 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12386 eclass = ExprClass.Value;
12390 public override object Accept (StructuralVisitor visitor)
12392 return visitor.Visit (this);
12396 public class AnonymousTypeParameter : ShimExpression
12398 public readonly string Name;
12400 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12401 : base (initializer)
12407 public AnonymousTypeParameter (Parameter parameter)
12408 : base (new SimpleName (parameter.Name, parameter.Location))
12410 this.Name = parameter.Name;
12411 this.loc = parameter.Location;
12414 public override bool Equals (object o)
12416 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12417 return other != null && Name == other.Name;
12420 public override int GetHashCode ()
12422 return Name.GetHashCode ();
12425 protected override Expression DoResolve (ResolveContext ec)
12427 Expression e = expr.Resolve (ec);
12431 if (e.eclass == ExprClass.MethodGroup) {
12432 Error_InvalidInitializer (ec, e.ExprClassName);
12437 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12438 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12445 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12447 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12448 Name, initializer);
12452 public class CatchFilterExpression : BooleanExpression
12454 public CatchFilterExpression (Expression expr, Location loc)
12461 public class InterpolatedString : Expression
12463 readonly StringLiteral start, end;
12464 List<Expression> interpolations;
12465 Arguments arguments;
12467 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12469 this.start = start;
12471 this.interpolations = interpolations;
12472 loc = start.Location;
12475 protected override void CloneTo (CloneContext clonectx, Expression t)
12477 InterpolatedString target = (InterpolatedString) t;
12479 if (interpolations != null) {
12480 target.interpolations = new List<Expression> ();
12481 foreach (var interpolation in interpolations) {
12482 target.interpolations.Add (interpolation.Clone (clonectx));
12487 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12489 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12490 if (factory == null)
12493 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12494 var res = new Invocation (ma, arguments).Resolve (rc);
12495 if (res != null && res.Type != type)
12496 res = Convert.ExplicitConversion (rc, res, type, loc);
12501 public override bool ContainsEmitWithAwait ()
12503 if (interpolations == null)
12506 foreach (var expr in interpolations) {
12507 if (expr.ContainsEmitWithAwait ())
12514 public override Expression CreateExpressionTree (ResolveContext rc)
12516 var best = ResolveBestFormatOverload (rc);
12520 Expression instance = new NullLiteral (loc);
12521 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12522 return CreateExpressionFactoryCall (rc, "Call", args);
12525 protected override Expression DoResolve (ResolveContext rc)
12529 if (interpolations == null) {
12531 arguments = new Arguments (1);
12533 for (int i = 0; i < interpolations.Count; i += 2) {
12534 var ipi = (InterpolatedStringInsert)interpolations [i];
12538 arguments = new Arguments (interpolations.Count);
12540 var sb = new StringBuilder (start.Value);
12541 for (int i = 0; i < interpolations.Count; ++i) {
12543 sb.Append ('{').Append (i / 2);
12544 var isi = (InterpolatedStringInsert)interpolations [i];
12545 if (isi.Alignment != null) {
12547 var value = isi.ResolveAligment (rc);
12549 sb.Append (value.Value);
12552 if (isi.Format != null) {
12554 sb.Append (isi.Format);
12558 arguments.Add (new Argument (interpolations [i]));
12560 sb.Append (((StringLiteral)interpolations [i]).Value);
12564 sb.Append (end.Value);
12565 str = sb.ToString ();
12568 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12570 eclass = ExprClass.Value;
12571 type = rc.BuiltinTypes.String;
12575 public override void Emit (EmitContext ec)
12577 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12578 if (interpolations == null) {
12579 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12580 if (str != start.Value)
12581 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12588 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12592 var ca = new CallEmitter ();
12593 ca.Emit (ec, best, arguments, loc);
12596 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12598 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12599 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12600 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12604 public class InterpolatedStringInsert : CompositeExpression
12606 public InterpolatedStringInsert (Expression expr)
12611 public Expression Alignment { get; set; }
12612 public string Format { get; set; }
12614 protected override void CloneTo (CloneContext clonectx, Expression t)
12616 var target = (InterpolatedStringInsert)t;
12617 target.expr = expr.Clone (clonectx);
12618 if (Alignment != null)
12619 target.Alignment = Alignment.Clone (clonectx);
12622 protected override Expression DoResolve (ResolveContext rc)
12624 var expr = base.DoResolve (rc);
12629 // For better error reporting, assumes the built-in implementation uses object
12632 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12635 public int? ResolveAligment (ResolveContext rc)
12637 var c = Alignment.ResolveLabelConstant (rc);
12641 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12645 var value = (int) c.GetValueAsLong ();
12646 if (value > 32767 || value < -32767) {
12647 rc.Report.Warning (8094, 1, Alignment.Location,
12648 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");