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 protected override Expression DoResolve (ResolveContext rc)
114 Expression res = null;
116 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
117 if (expr.HasConditionalAccess ()) {
118 conditional_access_receiver = true;
119 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
120 res = expr.Resolve (rc);
125 if (!conditional_access_receiver)
126 res = expr.Resolve (rc);
128 var constant = res as Constant;
129 if (constant != null && constant.IsLiteral)
130 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
132 if (conditional_access_receiver) {
134 type = LiftMemberType (rc, res.Type);
135 eclass = expr.eclass;
142 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
144 return expr.DoResolveLValue (ec, right_side);
147 public override object Accept (StructuralVisitor visitor)
149 return visitor.Visit (this);
152 public override void Emit (EmitContext ec)
154 if (!conditional_access_receiver)
157 var prev = ec.ConditionalAccess;
158 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
160 ec.CloseConditionalAccess (type.IsNullableType ? type : null);
161 ec.ConditionalAccess = prev;
164 public override bool HasConditionalAccess ()
171 // Unary implements unary expressions.
173 public class Unary : Expression
175 public enum Operator : byte {
176 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
180 public readonly Operator Oper;
181 public Expression Expr;
182 ConvCast.Mode enum_conversion;
184 public Unary (Operator op, Expression expr, Location loc)
192 // This routine will attempt to simplify the unary expression when the
193 // argument is a constant.
195 Constant TryReduceConstant (ResolveContext ec, Constant constant)
199 while (e is EmptyConstantCast)
200 e = ((EmptyConstantCast) e).child;
202 if (e is SideEffectConstant) {
203 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
204 return r == null ? null : new SideEffectConstant (r, e, r.Location);
207 TypeSpec expr_type = e.Type;
210 case Operator.UnaryPlus:
211 // Unary numeric promotions
212 switch (expr_type.BuiltinType) {
213 case BuiltinTypeSpec.Type.Byte:
214 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
215 case BuiltinTypeSpec.Type.SByte:
216 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
217 case BuiltinTypeSpec.Type.Short:
218 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
219 case BuiltinTypeSpec.Type.UShort:
220 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
221 case BuiltinTypeSpec.Type.Char:
222 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
224 // Predefined operators
225 case BuiltinTypeSpec.Type.Int:
226 case BuiltinTypeSpec.Type.UInt:
227 case BuiltinTypeSpec.Type.Long:
228 case BuiltinTypeSpec.Type.ULong:
229 case BuiltinTypeSpec.Type.Float:
230 case BuiltinTypeSpec.Type.Double:
231 case BuiltinTypeSpec.Type.Decimal:
237 case Operator.UnaryNegation:
238 // Unary numeric promotions
239 switch (expr_type.BuiltinType) {
240 case BuiltinTypeSpec.Type.Byte:
241 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
242 case BuiltinTypeSpec.Type.SByte:
243 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
244 case BuiltinTypeSpec.Type.Short:
245 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
246 case BuiltinTypeSpec.Type.UShort:
247 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
248 case BuiltinTypeSpec.Type.Char:
249 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
251 // Predefined operators
252 case BuiltinTypeSpec.Type.Int:
253 int ivalue = ((IntConstant) e).Value;
254 if (ivalue == int.MinValue) {
255 if (ec.ConstantCheckState) {
256 ConstantFold.Error_CompileTimeOverflow (ec, loc);
261 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
263 case BuiltinTypeSpec.Type.Long:
264 long lvalue = ((LongConstant) e).Value;
265 if (lvalue == long.MinValue) {
266 if (ec.ConstantCheckState) {
267 ConstantFold.Error_CompileTimeOverflow (ec, loc);
272 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
274 case BuiltinTypeSpec.Type.UInt:
275 UIntLiteral uil = constant as UIntLiteral;
277 if (uil.Value == int.MaxValue + (uint) 1)
278 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
279 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
281 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
284 case BuiltinTypeSpec.Type.ULong:
285 ULongLiteral ull = constant as ULongLiteral;
286 if (ull != null && ull.Value == 9223372036854775808)
287 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
290 case BuiltinTypeSpec.Type.Float:
291 FloatLiteral fl = constant as FloatLiteral;
292 // For better error reporting
294 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
296 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.Double:
299 DoubleLiteral dl = constant as DoubleLiteral;
300 // For better error reporting
302 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
304 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
306 case BuiltinTypeSpec.Type.Decimal:
307 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
312 case Operator.LogicalNot:
313 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
316 bool b = (bool)e.GetValue ();
317 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
319 case Operator.OnesComplement:
320 // Unary numeric promotions
321 switch (expr_type.BuiltinType) {
322 case BuiltinTypeSpec.Type.Byte:
323 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
324 case BuiltinTypeSpec.Type.SByte:
325 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
326 case BuiltinTypeSpec.Type.Short:
327 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
328 case BuiltinTypeSpec.Type.UShort:
329 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
330 case BuiltinTypeSpec.Type.Char:
331 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
333 // Predefined operators
334 case BuiltinTypeSpec.Type.Int:
335 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
336 case BuiltinTypeSpec.Type.UInt:
337 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
338 case BuiltinTypeSpec.Type.Long:
339 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
340 case BuiltinTypeSpec.Type.ULong:
341 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
343 if (e is EnumConstant) {
344 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
347 // Numeric promotion upgraded types to int but for enum constant
348 // original underlying constant type is needed
350 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
351 int v = ((IntConstant) res).Value;
352 switch (((EnumConstant) e).Child.Type.BuiltinType) {
353 case BuiltinTypeSpec.Type.UShort:
354 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
356 case BuiltinTypeSpec.Type.Short:
357 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
359 case BuiltinTypeSpec.Type.Byte:
360 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
362 case BuiltinTypeSpec.Type.SByte:
363 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
368 res = new EnumConstant (res, expr_type);
374 throw new Exception ("Can not constant fold: " + Oper.ToString());
377 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
379 eclass = ExprClass.Value;
381 TypeSpec expr_type = expr.Type;
382 Expression best_expr;
384 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
387 // Primitive types first
389 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
390 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
391 if (best_expr == null)
394 type = best_expr.Type;
400 // E operator ~(E x);
402 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
403 return ResolveEnumOperator (ec, expr, predefined);
405 return ResolveUserType (ec, expr, predefined);
408 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
410 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
411 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
412 if (best_expr == null)
416 enum_conversion = Binary.GetEnumResultCast (underlying_type);
418 return EmptyCast.Create (this, type);
421 public override bool ContainsEmitWithAwait ()
423 return Expr.ContainsEmitWithAwait ();
426 public override Expression CreateExpressionTree (ResolveContext ec)
428 return CreateExpressionTree (ec, null);
431 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
435 case Operator.AddressOf:
436 Error_PointerInsideExpressionTree (ec);
438 case Operator.UnaryNegation:
439 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
440 method_name = "NegateChecked";
442 method_name = "Negate";
444 case Operator.OnesComplement:
445 case Operator.LogicalNot:
448 case Operator.UnaryPlus:
449 method_name = "UnaryPlus";
452 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
455 Arguments args = new Arguments (2);
456 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
458 args.Add (new Argument (user_op));
460 return CreateExpressionFactoryCall (ec, method_name, args);
463 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
465 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
468 // 7.6.1 Unary plus operator
470 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong,
473 types.Float, types.Double,
478 // 7.6.2 Unary minus operator
480 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
481 types.Int, types.Long,
482 types.Float, types.Double,
487 // 7.6.3 Logical negation operator
489 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
494 // 7.6.4 Bitwise complement operator
496 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
497 types.Int, types.UInt,
498 types.Long, types.ULong
501 return predefined_operators;
505 // Unary numeric promotions
507 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
509 TypeSpec expr_type = expr.Type;
510 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
511 switch (expr_type.BuiltinType) {
512 case BuiltinTypeSpec.Type.Byte:
513 case BuiltinTypeSpec.Type.SByte:
514 case BuiltinTypeSpec.Type.Short:
515 case BuiltinTypeSpec.Type.UShort:
516 case BuiltinTypeSpec.Type.Char:
517 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
521 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
522 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
527 protected override Expression DoResolve (ResolveContext ec)
529 if (Oper == Operator.AddressOf) {
530 return ResolveAddressOf (ec);
533 Expr = Expr.Resolve (ec);
537 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
538 Arguments args = new Arguments (1);
539 args.Add (new Argument (Expr));
540 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
543 if (Expr.Type.IsNullableType)
544 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
547 // Attempt to use a constant folding operation.
549 Constant cexpr = Expr as Constant;
551 cexpr = TryReduceConstant (ec, cexpr);
556 Expression expr = ResolveOperator (ec, Expr);
558 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
561 // Reduce unary operator on predefined types
563 if (expr == this && Oper == Operator.UnaryPlus)
569 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
574 public override void Emit (EmitContext ec)
576 EmitOperator (ec, type);
579 protected void EmitOperator (EmitContext ec, TypeSpec type)
582 case Operator.UnaryPlus:
586 case Operator.UnaryNegation:
587 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
588 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
589 Expr = Expr.EmitToField (ec);
592 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
593 ec.Emit (OpCodes.Conv_U8);
595 ec.Emit (OpCodes.Sub_Ovf);
598 ec.Emit (OpCodes.Neg);
603 case Operator.LogicalNot:
606 ec.Emit (OpCodes.Ceq);
609 case Operator.OnesComplement:
611 ec.Emit (OpCodes.Not);
614 case Operator.AddressOf:
615 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
619 throw new Exception ("This should not happen: Operator = "
624 // Same trick as in Binary expression
626 if (enum_conversion != 0) {
627 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
628 ConvCast.Emit (ec, enum_conversion);
633 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
635 if (Oper == Operator.LogicalNot)
636 Expr.EmitBranchable (ec, target, !on_true);
638 base.EmitBranchable (ec, target, on_true);
641 public override void EmitSideEffect (EmitContext ec)
643 Expr.EmitSideEffect (ec);
646 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
648 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
649 oper, type.GetSignatureForError ());
652 public override void FlowAnalysis (FlowAnalysisContext fc)
654 FlowAnalysis (fc, false);
657 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
659 FlowAnalysis (fc, true);
662 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
664 if (Oper == Operator.AddressOf) {
665 var vr = Expr as VariableReference;
666 if (vr != null && vr.VariableInfo != null)
667 fc.SetVariableAssigned (vr.VariableInfo);
672 if (Oper == Operator.LogicalNot && conditional) {
673 Expr.FlowAnalysisConditional (fc);
675 var temp = fc.DefiniteAssignmentOnTrue;
676 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
677 fc.DefiniteAssignmentOnFalse = temp;
679 Expr.FlowAnalysis (fc);
684 // Converts operator to System.Linq.Expressions.ExpressionType enum name
686 string GetOperatorExpressionTypeName ()
689 case Operator.OnesComplement:
690 return "OnesComplement";
691 case Operator.LogicalNot:
693 case Operator.UnaryNegation:
695 case Operator.UnaryPlus:
698 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
702 static bool IsFloat (TypeSpec t)
704 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
708 // Returns a stringified representation of the Operator
710 public static string OperName (Operator oper)
713 case Operator.UnaryPlus:
715 case Operator.UnaryNegation:
717 case Operator.LogicalNot:
719 case Operator.OnesComplement:
721 case Operator.AddressOf:
725 throw new NotImplementedException (oper.ToString ());
728 public override SLE.Expression MakeExpression (BuilderContext ctx)
730 var expr = Expr.MakeExpression (ctx);
731 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
734 case Operator.UnaryNegation:
735 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
736 case Operator.LogicalNot:
737 return SLE.Expression.Not (expr);
738 case Operator.OnesComplement:
739 return SLE.Expression.OnesComplement (expr);
741 throw new NotImplementedException (Oper.ToString ());
745 Expression ResolveAddressOf (ResolveContext ec)
748 UnsafeError (ec, loc);
750 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
751 if (Expr == null || Expr.eclass != ExprClass.Variable) {
752 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
756 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
760 IVariableReference vr = Expr as IVariableReference;
763 is_fixed = vr.IsFixed;
764 vr.SetHasAddressTaken ();
767 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
770 IFixedExpression fe = Expr as IFixedExpression;
771 is_fixed = fe != null && fe.IsFixed;
774 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
775 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
778 type = PointerContainer.MakeType (ec.Module, Expr.Type);
779 eclass = ExprClass.Value;
783 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
785 expr = DoNumericPromotion (rc, Oper, expr);
786 TypeSpec expr_type = expr.Type;
787 foreach (TypeSpec t in predefined) {
795 // Perform user-operator overload resolution
797 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
799 CSharp.Operator.OpType op_type;
801 case Operator.LogicalNot:
802 op_type = CSharp.Operator.OpType.LogicalNot; break;
803 case Operator.OnesComplement:
804 op_type = CSharp.Operator.OpType.OnesComplement; break;
805 case Operator.UnaryNegation:
806 op_type = CSharp.Operator.OpType.UnaryNegation; break;
807 case Operator.UnaryPlus:
808 op_type = CSharp.Operator.OpType.UnaryPlus; break;
810 throw new InternalErrorException (Oper.ToString ());
813 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
817 Arguments args = new Arguments (1);
818 args.Add (new Argument (expr));
820 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
821 var oper = res.ResolveOperator (ec, ref args);
826 Expr = args [0].Expr;
827 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
831 // Unary user type overload resolution
833 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
835 Expression best_expr = ResolveUserOperator (ec, expr);
836 if (best_expr != null)
839 foreach (TypeSpec t in predefined) {
840 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
841 if (oper_expr == null)
844 if (oper_expr == ErrorExpression.Instance)
848 // decimal type is predefined but has user-operators
850 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
851 oper_expr = ResolveUserType (ec, oper_expr, predefined);
853 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
855 if (oper_expr == null)
858 if (best_expr == null) {
859 best_expr = oper_expr;
863 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
865 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
866 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
868 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
875 best_expr = oper_expr;
878 if (best_expr == null)
882 // HACK: Decimal user-operator is included in standard operators
884 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
888 type = best_expr.Type;
892 protected override void CloneTo (CloneContext clonectx, Expression t)
894 Unary target = (Unary) t;
896 target.Expr = Expr.Clone (clonectx);
899 public override object Accept (StructuralVisitor visitor)
901 return visitor.Visit (this);
907 // Unary operators are turned into Indirection expressions
908 // after semantic analysis (this is so we can take the address
909 // of an indirection).
911 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
913 LocalTemporary temporary;
916 public Indirection (Expression expr, Location l)
922 public Expression Expr {
928 public bool IsFixed {
932 public override Location StartLocation {
934 return expr.StartLocation;
938 protected override void CloneTo (CloneContext clonectx, Expression t)
940 Indirection target = (Indirection) t;
941 target.expr = expr.Clone (clonectx);
944 public override bool ContainsEmitWithAwait ()
946 throw new NotImplementedException ();
949 public override Expression CreateExpressionTree (ResolveContext ec)
951 Error_PointerInsideExpressionTree (ec);
955 public override void Emit (EmitContext ec)
960 ec.EmitLoadFromPtr (Type);
963 public void Emit (EmitContext ec, bool leave_copy)
967 ec.Emit (OpCodes.Dup);
968 temporary = new LocalTemporary (expr.Type);
969 temporary.Store (ec);
973 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
975 prepared = isCompound;
980 ec.Emit (OpCodes.Dup);
984 ec.Emit (OpCodes.Dup);
985 temporary = new LocalTemporary (source.Type);
986 temporary.Store (ec);
989 ec.EmitStoreFromPtr (type);
991 if (temporary != null) {
993 temporary.Release (ec);
997 public void AddressOf (EmitContext ec, AddressOp Mode)
1002 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1004 return DoResolve (ec);
1007 protected override Expression DoResolve (ResolveContext ec)
1009 expr = expr.Resolve (ec);
1014 UnsafeError (ec, loc);
1016 var pc = expr.Type as PointerContainer;
1019 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1025 if (type.Kind == MemberKind.Void) {
1026 Error_VoidPointerOperation (ec);
1030 eclass = ExprClass.Variable;
1034 public override object Accept (StructuralVisitor visitor)
1036 return visitor.Visit (this);
1041 /// Unary Mutator expressions (pre and post ++ and --)
1045 /// UnaryMutator implements ++ and -- expressions. It derives from
1046 /// ExpressionStatement becuase the pre/post increment/decrement
1047 /// operators can be used in a statement context.
1049 /// FIXME: Idea, we could split this up in two classes, one simpler
1050 /// for the common case, and one with the extra fields for more complex
1051 /// classes (indexers require temporary access; overloaded require method)
1054 public class UnaryMutator : ExpressionStatement
1056 class DynamicPostMutator : Expression, IAssignMethod
1058 LocalTemporary temp;
1061 public DynamicPostMutator (Expression expr)
1064 this.type = expr.Type;
1065 this.loc = expr.Location;
1068 public override Expression CreateExpressionTree (ResolveContext ec)
1070 throw new NotImplementedException ("ET");
1073 protected override Expression DoResolve (ResolveContext rc)
1075 eclass = expr.eclass;
1079 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1081 expr.DoResolveLValue (ec, right_side);
1082 return DoResolve (ec);
1085 public override void Emit (EmitContext ec)
1090 public void Emit (EmitContext ec, bool leave_copy)
1092 throw new NotImplementedException ();
1096 // Emits target assignment using unmodified source value
1098 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1101 // Allocate temporary variable to keep original value before it's modified
1103 temp = new LocalTemporary (type);
1107 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1118 public enum Mode : byte {
1125 PreDecrement = IsDecrement,
1126 PostIncrement = IsPost,
1127 PostDecrement = IsPost | IsDecrement
1131 bool is_expr, recurse;
1133 protected Expression expr;
1135 // Holds the real operation
1136 Expression operation;
1138 public UnaryMutator (Mode m, Expression e, Location loc)
1145 public Mode UnaryMutatorMode {
1151 public Expression Expr {
1157 public override Location StartLocation {
1159 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1163 public override bool ContainsEmitWithAwait ()
1165 return expr.ContainsEmitWithAwait ();
1168 public override Expression CreateExpressionTree (ResolveContext ec)
1170 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1173 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1176 // Predefined ++ and -- operators exist for the following types:
1177 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1179 return new TypeSpec[] {
1195 protected override Expression DoResolve (ResolveContext ec)
1197 expr = expr.Resolve (ec);
1199 if (expr == null || expr.Type == InternalType.ErrorType)
1202 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1204 // Handle postfix unary operators using local
1205 // temporary variable
1207 if ((mode & Mode.IsPost) != 0)
1208 expr = new DynamicPostMutator (expr);
1210 Arguments args = new Arguments (1);
1211 args.Add (new Argument (expr));
1212 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1215 if (expr.Type.IsNullableType)
1216 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1218 return DoResolveOperation (ec);
1221 protected Expression DoResolveOperation (ResolveContext ec)
1223 eclass = ExprClass.Value;
1226 if (expr is RuntimeValueExpression) {
1229 // Use itself at the top of the stack
1230 operation = new EmptyExpression (type);
1234 // The operand of the prefix/postfix increment decrement operators
1235 // should be an expression that is classified as a variable,
1236 // a property access or an indexer access
1238 // TODO: Move to parser, expr is ATypeNameExpression
1239 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1240 expr = expr.ResolveLValue (ec, expr);
1242 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1246 // Step 1: Try to find a user operator, it has priority over predefined ones
1248 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1249 var methods = MemberCache.GetUserOperator (type, user_op, false);
1251 if (methods != null) {
1252 Arguments args = new Arguments (1);
1253 args.Add (new Argument (expr));
1255 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1256 var method = res.ResolveOperator (ec, ref args);
1260 args[0].Expr = operation;
1261 operation = new UserOperatorCall (method, args, null, loc);
1262 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1267 // Step 2: Try predefined types
1270 Expression source = null;
1271 bool primitive_type;
1274 // Predefined without user conversion first for speed-up
1276 // Predefined ++ and -- operators exist for the following types:
1277 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1279 switch (type.BuiltinType) {
1280 case BuiltinTypeSpec.Type.Byte:
1281 case BuiltinTypeSpec.Type.SByte:
1282 case BuiltinTypeSpec.Type.Short:
1283 case BuiltinTypeSpec.Type.UShort:
1284 case BuiltinTypeSpec.Type.Int:
1285 case BuiltinTypeSpec.Type.UInt:
1286 case BuiltinTypeSpec.Type.Long:
1287 case BuiltinTypeSpec.Type.ULong:
1288 case BuiltinTypeSpec.Type.Char:
1289 case BuiltinTypeSpec.Type.Float:
1290 case BuiltinTypeSpec.Type.Double:
1291 case BuiltinTypeSpec.Type.Decimal:
1293 primitive_type = true;
1296 primitive_type = false;
1298 // ++/-- on pointer variables of all types except void*
1299 if (type.IsPointer) {
1300 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1301 Error_VoidPointerOperation (ec);
1307 Expression best_source = null;
1308 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1309 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1311 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1315 if (best_source == null) {
1316 best_source = source;
1320 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1325 best_source = source;
1329 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1333 source = best_source;
1336 // ++/-- on enum types
1337 if (source == null && type.IsEnum)
1340 if (source == null) {
1341 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1348 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1349 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1350 operation = new Binary (op, source, one);
1351 operation = operation.Resolve (ec);
1352 if (operation == null)
1353 throw new NotImplementedException ("should not be reached");
1355 if (operation.Type != type) {
1357 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1359 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1365 void EmitCode (EmitContext ec, bool is_expr)
1368 this.is_expr = is_expr;
1369 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1372 public override void Emit (EmitContext ec)
1375 // We use recurse to allow ourselfs to be the source
1376 // of an assignment. This little hack prevents us from
1377 // having to allocate another expression
1380 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1388 EmitCode (ec, true);
1391 protected virtual void EmitOperation (EmitContext ec)
1393 operation.Emit (ec);
1396 public override void EmitStatement (EmitContext ec)
1398 EmitCode (ec, false);
1401 public override void FlowAnalysis (FlowAnalysisContext fc)
1403 expr.FlowAnalysis (fc);
1407 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1409 string GetOperatorExpressionTypeName ()
1411 return IsDecrement ? "Decrement" : "Increment";
1415 get { return (mode & Mode.IsDecrement) != 0; }
1419 public override SLE.Expression MakeExpression (BuilderContext ctx)
1421 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1422 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1423 return SLE.Expression.Assign (target, source);
1426 public static string OperName (Mode oper)
1428 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1431 protected override void CloneTo (CloneContext clonectx, Expression t)
1433 UnaryMutator target = (UnaryMutator) t;
1435 target.expr = expr.Clone (clonectx);
1438 public override object Accept (StructuralVisitor visitor)
1440 return visitor.Visit (this);
1446 // Base class for the `is' and `as' operators
1448 public abstract class Probe : Expression
1450 public Expression ProbeType;
1451 protected Expression expr;
1452 protected TypeSpec probe_type_expr;
1454 protected Probe (Expression expr, Expression probe_type, Location l)
1456 ProbeType = probe_type;
1461 public Expression Expr {
1467 public override bool ContainsEmitWithAwait ()
1469 return expr.ContainsEmitWithAwait ();
1472 protected Expression ResolveCommon (ResolveContext rc)
1474 expr = expr.Resolve (rc);
1478 ResolveProbeType (rc);
1479 if (probe_type_expr == null)
1482 if (probe_type_expr.IsStatic) {
1483 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1484 probe_type_expr.GetSignatureForError ());
1488 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1489 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1494 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1495 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1503 protected virtual void ResolveProbeType (ResolveContext rc)
1505 probe_type_expr = ProbeType.ResolveAsType (rc);
1508 public override void EmitSideEffect (EmitContext ec)
1510 expr.EmitSideEffect (ec);
1513 public override void FlowAnalysis (FlowAnalysisContext fc)
1515 expr.FlowAnalysis (fc);
1518 public override bool HasConditionalAccess ()
1520 return expr.HasConditionalAccess ();
1523 protected abstract string OperatorName { get; }
1525 protected override void CloneTo (CloneContext clonectx, Expression t)
1527 Probe target = (Probe) t;
1529 target.expr = expr.Clone (clonectx);
1530 target.ProbeType = ProbeType.Clone (clonectx);
1536 /// Implementation of the `is' operator.
1538 public class Is : Probe
1540 Nullable.Unwrap expr_unwrap;
1541 MethodSpec number_mg;
1542 Arguments number_args;
1544 public Is (Expression expr, Expression probe_type, Location l)
1545 : base (expr, probe_type, l)
1549 protected override string OperatorName {
1550 get { return "is"; }
1553 public LocalVariable Variable { get; set; }
1555 public override Expression CreateExpressionTree (ResolveContext ec)
1557 if (Variable != null)
1558 throw new NotSupportedException ();
1560 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1561 expr.CreateExpressionTree (ec),
1562 new TypeOf (probe_type_expr, loc));
1564 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1567 Expression CreateConstantResult (ResolveContext rc, bool result)
1570 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1571 probe_type_expr.GetSignatureForError ());
1573 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1574 probe_type_expr.GetSignatureForError ());
1576 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1577 return expr.IsSideEffectFree ?
1578 ReducedExpression.Create (c, this) :
1579 new SideEffectConstant (c, this, loc);
1582 public override void Emit (EmitContext ec)
1584 if (probe_type_expr == null) {
1585 if (ProbeType is WildcardPattern) {
1586 expr.EmitSideEffect (ec);
1587 ProbeType.Emit (ec);
1589 EmitPatternMatch (ec);
1596 if (expr_unwrap == null) {
1598 ec.Emit (OpCodes.Cgt_Un);
1602 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1604 if (probe_type_expr == null) {
1605 EmitPatternMatch (ec);
1610 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1613 void EmitPatternMatch (EmitContext ec)
1615 var no_match = ec.DefineLabel ();
1616 var end = ec.DefineLabel ();
1618 if (expr_unwrap != null) {
1619 expr_unwrap.EmitCheck (ec);
1621 if (ProbeType.IsNull) {
1623 ec.Emit (OpCodes.Ceq);
1627 ec.Emit (OpCodes.Brfalse_S, no_match);
1628 expr_unwrap.Emit (ec);
1629 ProbeType.Emit (ec);
1630 ec.Emit (OpCodes.Ceq);
1631 ec.Emit (OpCodes.Br_S, end);
1632 ec.MarkLabel (no_match);
1638 if (number_args != null && number_args.Count == 3) {
1639 var ce = new CallEmitter ();
1640 ce.Emit (ec, number_mg, number_args, loc);
1644 var probe_type = ProbeType.Type;
1647 ec.Emit (OpCodes.Isinst, probe_type);
1648 ec.Emit (OpCodes.Dup);
1649 ec.Emit (OpCodes.Brfalse, no_match);
1651 bool complex_pattern = ProbeType is ComplexPatternExpression;
1652 Label prev = ec.RecursivePatternLabel;
1653 if (complex_pattern)
1654 ec.RecursivePatternLabel = ec.DefineLabel ();
1656 if (number_mg != null) {
1657 var ce = new CallEmitter ();
1658 ce.Emit (ec, number_mg, number_args, loc);
1660 if (TypeSpec.IsValueType (probe_type))
1661 ec.Emit (OpCodes.Unbox_Any, probe_type);
1663 ProbeType.Emit (ec);
1664 if (complex_pattern) {
1667 ec.Emit (OpCodes.Ceq);
1670 ec.Emit (OpCodes.Br_S, end);
1671 ec.MarkLabel (no_match);
1673 ec.Emit (OpCodes.Pop);
1675 if (complex_pattern)
1676 ec.MarkLabel (ec.RecursivePatternLabel);
1678 ec.RecursivePatternLabel = prev;
1684 void EmitLoad (EmitContext ec)
1686 Label no_value_label = new Label ();
1688 if (expr_unwrap != null) {
1689 expr_unwrap.EmitCheck (ec);
1691 if (Variable == null)
1694 ec.Emit (OpCodes.Dup);
1695 no_value_label = ec.DefineLabel ();
1696 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1697 expr_unwrap.Emit (ec);
1701 // Only to make verifier happy
1702 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1703 ec.Emit (OpCodes.Box, expr.Type);
1705 ec.Emit (OpCodes.Isinst, probe_type_expr);
1708 if (Variable != null) {
1709 bool value_on_stack;
1710 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1711 ec.Emit (OpCodes.Dup);
1712 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1713 value_on_stack = true;
1715 value_on_stack = false;
1718 Variable.CreateBuilder (ec);
1719 Variable.EmitAssign (ec);
1721 if (expr_unwrap != null) {
1722 ec.MarkLabel (no_value_label);
1723 } else if (!value_on_stack) {
1729 protected override Expression DoResolve (ResolveContext rc)
1731 if (ResolveCommon (rc) == null)
1734 type = rc.BuiltinTypes.Bool;
1735 eclass = ExprClass.Value;
1737 if (probe_type_expr == null)
1738 return ResolveMatchingExpression (rc);
1740 var res = ResolveResultExpression (rc);
1741 if (Variable != null) {
1742 if (res is Constant)
1743 throw new NotImplementedException ("constant in type pattern matching");
1745 Variable.Type = probe_type_expr;
1746 var bc = rc as BlockContext;
1748 Variable.PrepareAssignmentAnalysis (bc);
1754 public override void FlowAnalysis (FlowAnalysisContext fc)
1756 base.FlowAnalysis (fc);
1758 if (Variable != null)
1759 fc.SetVariableAssigned (Variable.VariableInfo, true);
1762 protected override void ResolveProbeType (ResolveContext rc)
1764 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1765 if (ProbeType is PatternExpression) {
1766 ProbeType.Resolve (rc);
1771 // Have to use session recording because we don't have reliable type probing
1772 // mechanism (similar issue as in attributes resolving)
1774 // TODO: This is still wrong because ResolveAsType can be destructive
1776 var type_printer = new SessionReportPrinter ();
1777 var prev_recorder = rc.Report.SetPrinter (type_printer);
1779 probe_type_expr = ProbeType.ResolveAsType (rc);
1780 type_printer.EndSession ();
1782 if (probe_type_expr != null) {
1783 type_printer.Merge (rc.Report.Printer);
1784 rc.Report.SetPrinter (prev_recorder);
1788 var vexpr = ProbeType as VarExpr;
1789 if (vexpr != null && vexpr.InferType (rc, expr)) {
1790 probe_type_expr = vexpr.Type;
1791 rc.Report.SetPrinter (prev_recorder);
1795 var expr_printer = new SessionReportPrinter ();
1796 rc.Report.SetPrinter (expr_printer);
1797 ProbeType = ProbeType.Resolve (rc);
1798 expr_printer.EndSession ();
1800 if (ProbeType != null) {
1801 expr_printer.Merge (rc.Report.Printer);
1803 type_printer.Merge (rc.Report.Printer);
1806 rc.Report.SetPrinter (prev_recorder);
1810 base.ResolveProbeType (rc);
1813 Expression ResolveMatchingExpression (ResolveContext rc)
1815 var mc = ProbeType as Constant;
1817 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1818 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1823 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1825 var c = Expr as Constant;
1827 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1832 if (Expr.Type.IsNullableType) {
1833 expr_unwrap = new Nullable.Unwrap (Expr);
1834 expr_unwrap.Resolve (rc);
1835 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1836 } else if (ProbeType.Type == Expr.Type) {
1837 // TODO: Better error handling
1838 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1839 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1840 var helper = rc.Module.CreatePatterMatchingHelper ();
1841 number_mg = helper.NumberMatcher.Spec;
1844 // There are actually 3 arguments but the first one is already on the stack
1846 number_args = new Arguments (3);
1847 if (!ProbeType.Type.IsEnum)
1848 number_args.Add (new Argument (Expr));
1850 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1851 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1857 if (ProbeType is PatternExpression) {
1858 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1859 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1865 // TODO: Better error message
1866 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1870 Expression ResolveResultExpression (ResolveContext ec)
1872 TypeSpec d = expr.Type;
1873 bool d_is_nullable = false;
1876 // If E is a method group or the null literal, or if the type of E is a reference
1877 // type or a nullable type and the value of E is null, the result is false
1879 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1880 return CreateConstantResult (ec, false);
1882 if (d.IsNullableType) {
1883 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1884 if (!ut.IsGenericParameter) {
1886 d_is_nullable = true;
1890 TypeSpec t = probe_type_expr;
1891 bool t_is_nullable = false;
1892 if (t.IsNullableType) {
1893 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1894 if (!ut.IsGenericParameter) {
1896 t_is_nullable = true;
1903 // D and T are the same value types but D can be null
1905 if (d_is_nullable && !t_is_nullable) {
1906 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1911 // The result is true if D and T are the same value types
1913 return CreateConstantResult (ec, true);
1916 var tp = d as TypeParameterSpec;
1918 return ResolveGenericParameter (ec, t, tp);
1921 // An unboxing conversion exists
1923 if (Convert.ExplicitReferenceConversionExists (d, t))
1927 // open generic type
1929 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1932 var tps = t as TypeParameterSpec;
1934 return ResolveGenericParameter (ec, d, tps);
1936 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1937 ec.Report.Warning (1981, 3, loc,
1938 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1939 OperatorName, t.GetSignatureForError ());
1942 if (TypeManager.IsGenericParameter (d))
1943 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1945 if (TypeSpec.IsValueType (d)) {
1946 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1947 if (d_is_nullable && !t_is_nullable) {
1948 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1952 return CreateConstantResult (ec, true);
1955 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1956 var c = expr as Constant;
1958 return CreateConstantResult (ec, !c.IsNull);
1961 // Do not optimize for imported type or dynamic type
1963 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1964 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1968 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1972 // Turn is check into simple null check for implicitly convertible reference types
1974 return ReducedExpression.Create (
1975 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1979 if (Convert.ExplicitReferenceConversionExists (d, t))
1983 // open generic type
1985 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1990 return CreateConstantResult (ec, false);
1993 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1995 if (t.IsReferenceType) {
1997 return CreateConstantResult (ec, false);
2000 if (expr.Type.IsGenericParameter) {
2001 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2002 return CreateConstantResult (ec, true);
2004 expr = new BoxedCast (expr, d);
2010 public override object Accept (StructuralVisitor visitor)
2012 return visitor.Visit (this);
2016 class WildcardPattern : PatternExpression
2018 public WildcardPattern (Location loc)
2023 protected override Expression DoResolve (ResolveContext rc)
2025 eclass = ExprClass.Value;
2026 type = rc.BuiltinTypes.Object;
2030 public override void Emit (EmitContext ec)
2036 class RecursivePattern : ComplexPatternExpression
2038 MethodGroupExpr operator_mg;
2039 Arguments operator_args;
2041 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2042 : base (typeExpresion, loc)
2044 Arguments = arguments;
2047 public Arguments Arguments { get; private set; }
2049 protected override Expression DoResolve (ResolveContext rc)
2051 type = TypeExpression.ResolveAsType (rc);
2055 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2056 if (operators == null) {
2057 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2061 var ops = FindMatchingOverloads (operators);
2063 // TODO: better error message
2064 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2069 Arguments.Resolve (rc, out dynamic_args);
2071 throw new NotImplementedException ("dynamic argument");
2073 var op = FindBestOverload (rc, ops);
2075 // TODO: better error message
2076 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2080 var op_types = op.Parameters.Types;
2081 operator_args = new Arguments (op_types.Length);
2082 operator_args.Add (new Argument (new EmptyExpression (type)));
2084 for (int i = 0; i < Arguments.Count; ++i) {
2085 // TODO: Needs releasing optimization
2086 var lt = new LocalTemporary (op_types [i + 1]);
2087 operator_args.Add (new Argument (lt, Argument.AType.Out));
2089 if (comparisons == null)
2090 comparisons = new Expression[Arguments.Count];
2095 var arg = Arguments [i];
2096 var named = arg as NamedArgument;
2097 if (named != null) {
2098 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2099 expr = Arguments [arg_comp_index].Expr;
2105 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2108 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2110 eclass = ExprClass.Value;
2114 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2116 int arg_count = Arguments.Count + 1;
2117 List<MethodSpec> best = null;
2118 foreach (MethodSpec method in members) {
2119 var pm = method.Parameters;
2120 if (pm.Count != arg_count)
2123 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2125 for (int ii = 1; ii < pm.Count; ++ii) {
2126 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2136 best = new List<MethodSpec> ();
2144 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2146 for (int ii = 0; ii < Arguments.Count; ++ii) {
2147 var arg = Arguments [ii];
2148 var expr = arg.Expr;
2149 if (expr is WildcardPattern)
2152 var na = arg as NamedArgument;
2153 for (int i = 0; i < methods.Count; ++i) {
2154 var pd = methods [i].Parameters;
2158 index = pd.GetParameterIndexByName (na.Name);
2160 methods.RemoveAt (i--);
2167 var m = pd.Types [index];
2168 if (!Convert.ImplicitConversionExists (rc, expr, m))
2169 methods.RemoveAt (i--);
2173 if (methods.Count != 1)
2179 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2181 operator_mg.EmitCall (ec, operator_args, false);
2182 ec.Emit (OpCodes.Brfalse, target);
2184 base.EmitBranchable (ec, target, on_true);
2187 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2189 if (expr is WildcardPattern)
2190 return new EmptyExpression (expr.Type);
2192 var recursive = expr as RecursivePattern;
2193 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2197 if (recursive != null) {
2198 recursive.SetParentInstance (lt);
2202 // TODO: Better error handling
2203 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2206 public void SetParentInstance (Expression instance)
2208 operator_args [0] = new Argument (instance);
2212 class PropertyPattern : ComplexPatternExpression
2214 LocalTemporary instance;
2216 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2217 : base (typeExpresion, loc)
2222 public List<PropertyPatternMember> Members { get; private set; }
2224 protected override Expression DoResolve (ResolveContext rc)
2226 type = TypeExpression.ResolveAsType (rc);
2230 comparisons = new Expression[Members.Count];
2232 // TODO: optimize when source is VariableReference, it'd save dup+pop
2233 instance = new LocalTemporary (type);
2235 for (int i = 0; i < Members.Count; i++) {
2236 var lookup = Members [i];
2238 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2239 if (member == null) {
2240 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2241 if (member != null) {
2242 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2247 if (member == null) {
2248 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2252 var pe = member as PropertyExpr;
2253 if (pe == null || member is FieldExpr) {
2254 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2258 // TODO: Obsolete checks
2259 // TODO: check accessibility
2260 if (pe != null && !pe.PropertyInfo.HasGet) {
2261 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2265 var expr = lookup.Expr.Resolve (rc);
2269 var me = (MemberExpr)member;
2270 me.InstanceExpression = instance;
2272 comparisons [i] = ResolveComparison (rc, expr, me);
2275 eclass = ExprClass.Value;
2279 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2281 if (expr is WildcardPattern)
2282 return new EmptyExpression (expr.Type);
2284 return new Is (instance, expr, expr.Location).Resolve (rc);
2287 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2289 instance.Store (ec);
2291 base.EmitBranchable (ec, target, on_true);
2295 class PropertyPatternMember
2297 public PropertyPatternMember (string name, Expression expr, Location loc)
2304 public string Name { get; private set; }
2305 public Expression Expr { get; private set; }
2306 public Location Location { get; private set; }
2309 abstract class PatternExpression : Expression
2311 protected PatternExpression (Location loc)
2316 public override Expression CreateExpressionTree (ResolveContext ec)
2318 throw new NotImplementedException ();
2322 abstract class ComplexPatternExpression : PatternExpression
2324 protected Expression[] comparisons;
2326 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2329 TypeExpression = typeExpresion;
2332 public ATypeNameExpression TypeExpression { get; private set; }
2334 public override void Emit (EmitContext ec)
2336 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2339 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2341 if (comparisons != null) {
2342 foreach (var comp in comparisons) {
2343 comp.EmitBranchable (ec, target, false);
2350 /// Implementation of the `as' operator.
2352 public class As : Probe {
2354 public As (Expression expr, Expression probe_type, Location l)
2355 : base (expr, probe_type, l)
2359 protected override string OperatorName {
2360 get { return "as"; }
2363 public override Expression CreateExpressionTree (ResolveContext ec)
2365 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2366 expr.CreateExpressionTree (ec),
2367 new TypeOf (probe_type_expr, loc));
2369 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2372 public override void Emit (EmitContext ec)
2376 ec.Emit (OpCodes.Isinst, type);
2378 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2379 ec.Emit (OpCodes.Unbox_Any, type);
2382 protected override Expression DoResolve (ResolveContext ec)
2384 if (ResolveCommon (ec) == null)
2387 type = probe_type_expr;
2388 eclass = ExprClass.Value;
2389 TypeSpec etype = expr.Type;
2391 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2392 if (TypeManager.IsGenericParameter (type)) {
2393 ec.Report.Error (413, loc,
2394 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2395 probe_type_expr.GetSignatureForError ());
2397 ec.Report.Error (77, loc,
2398 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2399 type.GetSignatureForError ());
2404 if (expr.IsNull && type.IsNullableType) {
2405 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2408 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2409 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2413 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2415 e = EmptyCast.Create (e, type);
2416 return ReducedExpression.Create (e, this).Resolve (ec);
2419 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2420 if (TypeManager.IsGenericParameter (etype))
2421 expr = new BoxedCast (expr, etype);
2426 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2427 expr = new BoxedCast (expr, etype);
2431 if (etype != InternalType.ErrorType) {
2432 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2433 etype.GetSignatureForError (), type.GetSignatureForError ());
2439 public override object Accept (StructuralVisitor visitor)
2441 return visitor.Visit (this);
2446 // This represents a typecast in the source language.
2448 public class Cast : ShimExpression {
2449 Expression target_type;
2451 public Cast (Expression cast_type, Expression expr, Location loc)
2454 this.target_type = cast_type;
2458 public Expression TargetType {
2459 get { return target_type; }
2462 protected override Expression DoResolve (ResolveContext ec)
2464 expr = expr.Resolve (ec);
2468 type = target_type.ResolveAsType (ec);
2472 if (type.IsStatic) {
2473 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2477 if (type.IsPointer && !ec.IsUnsafe) {
2478 UnsafeError (ec, loc);
2481 eclass = ExprClass.Value;
2483 Constant c = expr as Constant;
2485 c = c.Reduce (ec, type);
2490 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2492 return EmptyCast.Create (res, type);
2497 protected override void CloneTo (CloneContext clonectx, Expression t)
2499 Cast target = (Cast) t;
2501 target.target_type = target_type.Clone (clonectx);
2502 target.expr = expr.Clone (clonectx);
2505 public override object Accept (StructuralVisitor visitor)
2507 return visitor.Visit (this);
2511 public class ImplicitCast : ShimExpression
2515 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2518 this.loc = expr.Location;
2520 this.arrayAccess = arrayAccess;
2523 protected override Expression DoResolve (ResolveContext ec)
2525 expr = expr.Resolve (ec);
2530 expr = ConvertExpressionToArrayIndex (ec, expr);
2532 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2538 public class DeclarationExpression : Expression, IMemoryLocation
2540 LocalVariableReference lvr;
2542 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2544 VariableType = variableType;
2545 Variable = variable;
2546 this.loc = variable.Location;
2549 public LocalVariable Variable { get; set; }
2550 public Expression Initializer { get; set; }
2551 public FullNamedExpression VariableType { get; set; }
2553 public void AddressOf (EmitContext ec, AddressOp mode)
2555 Variable.CreateBuilder (ec);
2557 if (Initializer != null) {
2558 lvr.EmitAssign (ec, Initializer, false, false);
2561 lvr.AddressOf (ec, mode);
2564 protected override void CloneTo (CloneContext clonectx, Expression t)
2566 var target = (DeclarationExpression) t;
2568 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2570 if (Initializer != null)
2571 target.Initializer = Initializer.Clone (clonectx);
2574 public override Expression CreateExpressionTree (ResolveContext rc)
2576 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2580 bool DoResolveCommon (ResolveContext rc)
2582 var var_expr = VariableType as VarExpr;
2583 if (var_expr != null) {
2584 type = InternalType.VarOutType;
2586 type = VariableType.ResolveAsType (rc);
2591 if (Initializer != null) {
2592 Initializer = Initializer.Resolve (rc);
2594 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2595 type = var_expr.Type;
2599 Variable.Type = type;
2600 lvr = new LocalVariableReference (Variable, loc);
2602 eclass = ExprClass.Variable;
2606 protected override Expression DoResolve (ResolveContext rc)
2608 if (DoResolveCommon (rc))
2614 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2616 if (lvr == null && DoResolveCommon (rc))
2617 lvr.ResolveLValue (rc, right_side);
2622 public override void Emit (EmitContext ec)
2624 throw new NotImplementedException ();
2629 // C# 2.0 Default value expression
2631 public class DefaultValueExpression : Expression
2635 public DefaultValueExpression (Expression expr, Location loc)
2641 public Expression Expr {
2647 public override bool IsSideEffectFree {
2653 public override bool ContainsEmitWithAwait ()
2658 public override Expression CreateExpressionTree (ResolveContext ec)
2660 Arguments args = new Arguments (2);
2661 args.Add (new Argument (this));
2662 args.Add (new Argument (new TypeOf (type, loc)));
2663 return CreateExpressionFactoryCall (ec, "Constant", args);
2666 protected override Expression DoResolve (ResolveContext ec)
2668 type = expr.ResolveAsType (ec);
2672 if (type.IsStatic) {
2673 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2677 return new NullLiteral (Location).ConvertImplicitly (type);
2679 if (TypeSpec.IsReferenceType (type))
2680 return new NullConstant (type, loc);
2682 Constant c = New.Constantify (type, expr.Location);
2686 eclass = ExprClass.Variable;
2690 public override void Emit (EmitContext ec)
2692 LocalTemporary temp_storage = new LocalTemporary(type);
2694 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2695 ec.Emit(OpCodes.Initobj, type);
2696 temp_storage.Emit(ec);
2697 temp_storage.Release (ec);
2701 public override SLE.Expression MakeExpression (BuilderContext ctx)
2703 return SLE.Expression.Default (type.GetMetaInfo ());
2707 protected override void CloneTo (CloneContext clonectx, Expression t)
2709 DefaultValueExpression target = (DefaultValueExpression) t;
2711 target.expr = expr.Clone (clonectx);
2714 public override object Accept (StructuralVisitor visitor)
2716 return visitor.Visit (this);
2721 /// Binary operators
2723 public class Binary : Expression, IDynamicBinder
2725 public class PredefinedOperator
2727 protected readonly TypeSpec left;
2728 protected readonly TypeSpec right;
2729 protected readonly TypeSpec left_unwrap;
2730 protected readonly TypeSpec right_unwrap;
2731 public readonly Operator OperatorsMask;
2732 public TypeSpec ReturnType;
2734 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2735 : this (ltype, rtype, op_mask, ltype)
2739 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2740 : this (type, type, op_mask, return_type)
2744 public PredefinedOperator (TypeSpec type, Operator op_mask)
2745 : this (type, type, op_mask, type)
2749 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2751 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2752 throw new InternalErrorException ("Only masked values can be used");
2754 if ((op_mask & Operator.NullableMask) != 0) {
2755 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2756 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2758 left_unwrap = ltype;
2759 right_unwrap = rtype;
2764 this.OperatorsMask = op_mask;
2765 this.ReturnType = return_type;
2768 public bool IsLifted {
2770 return (OperatorsMask & Operator.NullableMask) != 0;
2774 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2778 var left_expr = b.left;
2779 var right_expr = b.right;
2781 b.type = ReturnType;
2784 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2785 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2786 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2789 if (right_expr.IsNull) {
2790 if ((b.oper & Operator.EqualityMask) != 0) {
2791 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2792 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2793 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2794 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2795 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2797 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2798 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2800 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2801 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2803 return b.CreateLiftedValueTypeResult (rc, left);
2805 } else if (left_expr.IsNull) {
2806 if ((b.oper & Operator.EqualityMask) != 0) {
2807 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2808 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2809 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2810 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2811 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2813 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2814 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2816 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2817 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2819 return b.CreateLiftedValueTypeResult (rc, right);
2825 // A user operators does not support multiple user conversions, but decimal type
2826 // is considered to be predefined type therefore we apply predefined operators rules
2827 // and then look for decimal user-operator implementation
2829 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2830 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2831 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2833 return b.ResolveUserOperator (rc, b.left, b.right);
2836 c = right_expr as Constant;
2838 if (c.IsDefaultValue) {
2842 // (expr + 0) to expr
2843 // (expr - 0) to expr
2844 // (bool? | false) to bool?
2846 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2847 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2848 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2849 return ReducedExpression.Create (b.left, b).Resolve (rc);
2853 // Optimizes (value &/&& 0) to 0
2855 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2856 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2857 return ReducedExpression.Create (side_effect, b);
2861 // Optimizes (bool? & true) to bool?
2863 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2864 return ReducedExpression.Create (b.left, b).Resolve (rc);
2868 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2869 return ReducedExpression.Create (b.left, b).Resolve (rc);
2871 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2872 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2876 c = b.left as Constant;
2878 if (c.IsDefaultValue) {
2882 // (0 + expr) to expr
2883 // (false | bool?) to bool?
2885 if (b.oper == Operator.Addition ||
2886 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2887 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2888 return ReducedExpression.Create (b.right, b).Resolve (rc);
2892 // Optimizes (false && expr) to false
2894 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2895 // No rhs side-effects
2896 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2897 return ReducedExpression.Create (c, b);
2901 // Optimizes (0 & value) to 0
2903 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2904 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2905 return ReducedExpression.Create (side_effect, b);
2909 // Optimizes (true & bool?) to bool?
2911 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2912 return ReducedExpression.Create (b.right, b).Resolve (rc);
2916 // Optimizes (true || expr) to true
2918 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2919 // No rhs side-effects
2920 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2921 return ReducedExpression.Create (c, b);
2925 if (b.oper == Operator.Multiply && c.IsOneInteger)
2926 return ReducedExpression.Create (b.right, b).Resolve (rc);
2930 var lifted = new Nullable.LiftedBinaryOperator (b);
2932 TypeSpec ltype, rtype;
2933 if (b.left.Type.IsNullableType) {
2934 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2935 ltype = left_unwrap;
2940 if (b.right.Type.IsNullableType) {
2941 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2942 rtype = right_unwrap;
2947 lifted.Left = b.left.IsNull ?
2949 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2951 lifted.Right = b.right.IsNull ?
2953 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2955 return lifted.Resolve (rc);
2958 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2959 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2964 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2967 // We are dealing with primitive types only
2969 return left == ltype && ltype == rtype;
2972 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2975 if (left == lexpr.Type && right == rexpr.Type)
2978 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2979 Convert.ImplicitConversionExists (ec, rexpr, right);
2982 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2984 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2985 return best_operator;
2987 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2991 if (left != null && best_operator.left != null) {
2992 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2996 // When second argument is same as the first one, the result is same
2998 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2999 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3002 if (result == 0 || result > 2)
3005 return result == 1 ? best_operator : this;
3009 sealed class PredefinedStringOperator : PredefinedOperator
3011 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3012 : base (type, type, op_mask, retType)
3016 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3017 : base (ltype, rtype, op_mask, retType)
3021 public override Expression ConvertResult (ResolveContext ec, Binary b)
3024 // Use original expression for nullable arguments
3026 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3028 b.left = unwrap.Original;
3030 unwrap = b.right as Nullable.Unwrap;
3032 b.right = unwrap.Original;
3034 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3035 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3038 // Start a new concat expression using converted expression
3040 return StringConcat.Create (ec, b.left, b.right, b.loc);
3044 sealed class PredefinedEqualityOperator : PredefinedOperator
3046 MethodSpec equal_method, inequal_method;
3048 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3049 : base (arg, arg, Operator.EqualityMask, retType)
3053 public override Expression ConvertResult (ResolveContext ec, Binary b)
3055 b.type = ReturnType;
3057 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3058 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3060 Arguments args = new Arguments (2);
3061 args.Add (new Argument (b.left));
3062 args.Add (new Argument (b.right));
3065 if (b.oper == Operator.Equality) {
3066 if (equal_method == null) {
3067 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3068 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3069 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3070 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3072 throw new NotImplementedException (left.GetSignatureForError ());
3075 method = equal_method;
3077 if (inequal_method == null) {
3078 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3079 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3080 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3081 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3083 throw new NotImplementedException (left.GetSignatureForError ());
3086 method = inequal_method;
3089 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3093 class PredefinedPointerOperator : PredefinedOperator
3095 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3096 : base (ltype, rtype, op_mask)
3100 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3101 : base (ltype, rtype, op_mask, retType)
3105 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3106 : base (type, op_mask, return_type)
3110 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3113 if (!lexpr.Type.IsPointer)
3116 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3120 if (right == null) {
3121 if (!rexpr.Type.IsPointer)
3124 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3131 public override Expression ConvertResult (ResolveContext ec, Binary b)
3134 b.left = EmptyCast.Create (b.left, left);
3135 } else if (right != null) {
3136 b.right = EmptyCast.Create (b.right, right);
3139 TypeSpec r_type = ReturnType;
3140 Expression left_arg, right_arg;
3141 if (r_type == null) {
3144 right_arg = b.right;
3145 r_type = b.left.Type;
3149 r_type = b.right.Type;
3153 right_arg = b.right;
3156 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3161 public enum Operator {
3162 Multiply = 0 | ArithmeticMask,
3163 Division = 1 | ArithmeticMask,
3164 Modulus = 2 | ArithmeticMask,
3165 Addition = 3 | ArithmeticMask | AdditionMask,
3166 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3168 LeftShift = 5 | ShiftMask,
3169 RightShift = 6 | ShiftMask,
3171 LessThan = 7 | ComparisonMask | RelationalMask,
3172 GreaterThan = 8 | ComparisonMask | RelationalMask,
3173 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3174 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3175 Equality = 11 | ComparisonMask | EqualityMask,
3176 Inequality = 12 | ComparisonMask | EqualityMask,
3178 BitwiseAnd = 13 | BitwiseMask,
3179 ExclusiveOr = 14 | BitwiseMask,
3180 BitwiseOr = 15 | BitwiseMask,
3182 LogicalAnd = 16 | LogicalMask,
3183 LogicalOr = 17 | LogicalMask,
3188 ValuesOnlyMask = ArithmeticMask - 1,
3189 ArithmeticMask = 1 << 5,
3191 ComparisonMask = 1 << 7,
3192 EqualityMask = 1 << 8,
3193 BitwiseMask = 1 << 9,
3194 LogicalMask = 1 << 10,
3195 AdditionMask = 1 << 11,
3196 SubtractionMask = 1 << 12,
3197 RelationalMask = 1 << 13,
3199 DecomposedMask = 1 << 19,
3200 NullableMask = 1 << 20
3204 public enum State : byte
3208 UserOperatorsExcluded = 1 << 2
3211 readonly Operator oper;
3212 Expression left, right;
3214 ConvCast.Mode enum_conversion;
3216 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3217 : this (oper, left, right, State.Compound)
3221 public Binary (Operator oper, Expression left, Expression right, State state)
3222 : this (oper, left, right)
3227 public Binary (Operator oper, Expression left, Expression right)
3228 : this (oper, left, right, left.Location)
3232 public Binary (Operator oper, Expression left, Expression right, Location loc)
3242 public bool IsCompound {
3244 return (state & State.Compound) != 0;
3248 public Operator Oper {
3254 public Expression Left {
3260 public Expression Right {
3266 public override Location StartLocation {
3268 return left.StartLocation;
3275 /// Returns a stringified representation of the Operator
3277 string OperName (Operator oper)
3281 case Operator.Multiply:
3284 case Operator.Division:
3287 case Operator.Modulus:
3290 case Operator.Addition:
3293 case Operator.Subtraction:
3296 case Operator.LeftShift:
3299 case Operator.RightShift:
3302 case Operator.LessThan:
3305 case Operator.GreaterThan:
3308 case Operator.LessThanOrEqual:
3311 case Operator.GreaterThanOrEqual:
3314 case Operator.Equality:
3317 case Operator.Inequality:
3320 case Operator.BitwiseAnd:
3323 case Operator.BitwiseOr:
3326 case Operator.ExclusiveOr:
3329 case Operator.LogicalOr:
3332 case Operator.LogicalAnd:
3336 s = oper.ToString ();
3346 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3348 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3351 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3353 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3357 l = left.Type.GetSignatureForError ();
3358 r = right.Type.GetSignatureForError ();
3360 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3364 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3366 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3369 public override void FlowAnalysis (FlowAnalysisContext fc)
3372 // Optimized version when on-true/on-false data are not needed
3374 if ((oper & Operator.LogicalMask) == 0) {
3375 left.FlowAnalysis (fc);
3376 right.FlowAnalysis (fc);
3380 left.FlowAnalysisConditional (fc);
3381 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3382 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3384 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3385 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3386 right.FlowAnalysisConditional (fc);
3388 if (oper == Operator.LogicalOr)
3389 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3391 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3394 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3396 if ((oper & Operator.LogicalMask) == 0) {
3397 base.FlowAnalysisConditional (fc);
3401 left.FlowAnalysisConditional (fc);
3402 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3403 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3405 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3406 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3407 right.FlowAnalysisConditional (fc);
3409 var lc = left as Constant;
3410 if (oper == Operator.LogicalOr) {
3411 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3412 if (lc != null && lc.IsDefaultValue)
3413 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3415 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3417 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3418 if (lc != null && !lc.IsDefaultValue)
3419 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3421 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3426 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3428 string GetOperatorExpressionTypeName ()
3431 case Operator.Addition:
3432 return IsCompound ? "AddAssign" : "Add";
3433 case Operator.BitwiseAnd:
3434 return IsCompound ? "AndAssign" : "And";
3435 case Operator.BitwiseOr:
3436 return IsCompound ? "OrAssign" : "Or";
3437 case Operator.Division:
3438 return IsCompound ? "DivideAssign" : "Divide";
3439 case Operator.ExclusiveOr:
3440 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3441 case Operator.Equality:
3443 case Operator.GreaterThan:
3444 return "GreaterThan";
3445 case Operator.GreaterThanOrEqual:
3446 return "GreaterThanOrEqual";
3447 case Operator.Inequality:
3449 case Operator.LeftShift:
3450 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3451 case Operator.LessThan:
3453 case Operator.LessThanOrEqual:
3454 return "LessThanOrEqual";
3455 case Operator.LogicalAnd:
3457 case Operator.LogicalOr:
3459 case Operator.Modulus:
3460 return IsCompound ? "ModuloAssign" : "Modulo";
3461 case Operator.Multiply:
3462 return IsCompound ? "MultiplyAssign" : "Multiply";
3463 case Operator.RightShift:
3464 return IsCompound ? "RightShiftAssign" : "RightShift";
3465 case Operator.Subtraction:
3466 return IsCompound ? "SubtractAssign" : "Subtract";
3468 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3472 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3475 case Operator.Addition:
3476 return CSharp.Operator.OpType.Addition;
3477 case Operator.BitwiseAnd:
3478 case Operator.LogicalAnd:
3479 return CSharp.Operator.OpType.BitwiseAnd;
3480 case Operator.BitwiseOr:
3481 case Operator.LogicalOr:
3482 return CSharp.Operator.OpType.BitwiseOr;
3483 case Operator.Division:
3484 return CSharp.Operator.OpType.Division;
3485 case Operator.Equality:
3486 return CSharp.Operator.OpType.Equality;
3487 case Operator.ExclusiveOr:
3488 return CSharp.Operator.OpType.ExclusiveOr;
3489 case Operator.GreaterThan:
3490 return CSharp.Operator.OpType.GreaterThan;
3491 case Operator.GreaterThanOrEqual:
3492 return CSharp.Operator.OpType.GreaterThanOrEqual;
3493 case Operator.Inequality:
3494 return CSharp.Operator.OpType.Inequality;
3495 case Operator.LeftShift:
3496 return CSharp.Operator.OpType.LeftShift;
3497 case Operator.LessThan:
3498 return CSharp.Operator.OpType.LessThan;
3499 case Operator.LessThanOrEqual:
3500 return CSharp.Operator.OpType.LessThanOrEqual;
3501 case Operator.Modulus:
3502 return CSharp.Operator.OpType.Modulus;
3503 case Operator.Multiply:
3504 return CSharp.Operator.OpType.Multiply;
3505 case Operator.RightShift:
3506 return CSharp.Operator.OpType.RightShift;
3507 case Operator.Subtraction:
3508 return CSharp.Operator.OpType.Subtraction;
3510 throw new InternalErrorException (op.ToString ());
3514 public override bool ContainsEmitWithAwait ()
3516 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3519 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3524 case Operator.Multiply:
3525 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3526 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3527 opcode = OpCodes.Mul_Ovf;
3528 else if (!IsFloat (l))
3529 opcode = OpCodes.Mul_Ovf_Un;
3531 opcode = OpCodes.Mul;
3533 opcode = OpCodes.Mul;
3537 case Operator.Division:
3539 opcode = OpCodes.Div_Un;
3541 opcode = OpCodes.Div;
3544 case Operator.Modulus:
3546 opcode = OpCodes.Rem_Un;
3548 opcode = OpCodes.Rem;
3551 case Operator.Addition:
3552 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3553 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3554 opcode = OpCodes.Add_Ovf;
3555 else if (!IsFloat (l))
3556 opcode = OpCodes.Add_Ovf_Un;
3558 opcode = OpCodes.Add;
3560 opcode = OpCodes.Add;
3563 case Operator.Subtraction:
3564 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3565 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3566 opcode = OpCodes.Sub_Ovf;
3567 else if (!IsFloat (l))
3568 opcode = OpCodes.Sub_Ovf_Un;
3570 opcode = OpCodes.Sub;
3572 opcode = OpCodes.Sub;
3575 case Operator.RightShift:
3576 if (!(right is IntConstant)) {
3577 ec.EmitInt (GetShiftMask (l));
3578 ec.Emit (OpCodes.And);
3582 opcode = OpCodes.Shr_Un;
3584 opcode = OpCodes.Shr;
3587 case Operator.LeftShift:
3588 if (!(right is IntConstant)) {
3589 ec.EmitInt (GetShiftMask (l));
3590 ec.Emit (OpCodes.And);
3593 opcode = OpCodes.Shl;
3596 case Operator.Equality:
3597 opcode = OpCodes.Ceq;
3600 case Operator.Inequality:
3601 ec.Emit (OpCodes.Ceq);
3604 opcode = OpCodes.Ceq;
3607 case Operator.LessThan:
3609 opcode = OpCodes.Clt_Un;
3611 opcode = OpCodes.Clt;
3614 case Operator.GreaterThan:
3616 opcode = OpCodes.Cgt_Un;
3618 opcode = OpCodes.Cgt;
3621 case Operator.LessThanOrEqual:
3622 if (IsUnsigned (l) || IsFloat (l))
3623 ec.Emit (OpCodes.Cgt_Un);
3625 ec.Emit (OpCodes.Cgt);
3628 opcode = OpCodes.Ceq;
3631 case Operator.GreaterThanOrEqual:
3632 if (IsUnsigned (l) || IsFloat (l))
3633 ec.Emit (OpCodes.Clt_Un);
3635 ec.Emit (OpCodes.Clt);
3639 opcode = OpCodes.Ceq;
3642 case Operator.BitwiseOr:
3643 opcode = OpCodes.Or;
3646 case Operator.BitwiseAnd:
3647 opcode = OpCodes.And;
3650 case Operator.ExclusiveOr:
3651 opcode = OpCodes.Xor;
3655 throw new InternalErrorException (oper.ToString ());
3661 static int GetShiftMask (TypeSpec type)
3663 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3666 static bool IsUnsigned (TypeSpec t)
3668 switch (t.BuiltinType) {
3669 case BuiltinTypeSpec.Type.Char:
3670 case BuiltinTypeSpec.Type.UInt:
3671 case BuiltinTypeSpec.Type.ULong:
3672 case BuiltinTypeSpec.Type.UShort:
3673 case BuiltinTypeSpec.Type.Byte:
3680 static bool IsFloat (TypeSpec t)
3682 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3685 public Expression ResolveOperator (ResolveContext rc)
3687 eclass = ExprClass.Value;
3689 TypeSpec l = left.Type;
3690 TypeSpec r = right.Type;
3692 bool primitives_only = false;
3695 // Handles predefined primitive types
3697 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3698 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3699 if ((oper & Operator.ShiftMask) == 0) {
3700 if (!DoBinaryOperatorPromotion (rc))
3703 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3707 if (l.IsPointer || r.IsPointer)
3708 return ResolveOperatorPointer (rc, l, r);
3711 if ((state & State.UserOperatorsExcluded) == 0) {
3712 expr = ResolveUserOperator (rc, left, right);
3717 bool lenum = l.IsEnum;
3718 bool renum = r.IsEnum;
3719 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3723 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3724 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3729 if ((oper & Operator.BitwiseMask) != 0) {
3730 expr = EmptyCast.Create (expr, type);
3731 enum_conversion = GetEnumResultCast (type);
3733 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3734 expr = OptimizeAndOperation (expr);
3738 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3739 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3742 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3743 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3747 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3750 // We cannot break here there is also Enum + String possible match
3751 // which is not ambiguous with predefined enum operators
3754 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3755 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3759 } else if (l.IsDelegate || r.IsDelegate) {
3763 expr = ResolveOperatorDelegate (rc, l, r);
3765 // TODO: Can this be ambiguous
3773 // Equality operators are more complicated
3775 if ((oper & Operator.EqualityMask) != 0) {
3776 return ResolveEquality (rc, l, r, primitives_only);
3779 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3783 if (primitives_only)
3787 // Lifted operators have lower priority
3789 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3792 static bool IsEnumOrNullableEnum (TypeSpec type)
3794 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3798 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3799 // if 'left' is not an enumeration constant, create one from the type of 'right'
3800 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3803 case Operator.BitwiseOr:
3804 case Operator.BitwiseAnd:
3805 case Operator.ExclusiveOr:
3806 case Operator.Equality:
3807 case Operator.Inequality:
3808 case Operator.LessThan:
3809 case Operator.LessThanOrEqual:
3810 case Operator.GreaterThan:
3811 case Operator.GreaterThanOrEqual:
3812 if (left.Type.IsEnum)
3815 if (left.IsZeroInteger)
3816 return left.Reduce (ec, right.Type);
3820 case Operator.Addition:
3821 case Operator.Subtraction:
3824 case Operator.Multiply:
3825 case Operator.Division:
3826 case Operator.Modulus:
3827 case Operator.LeftShift:
3828 case Operator.RightShift:
3829 if (right.Type.IsEnum || left.Type.IsEnum)
3838 // The `|' operator used on types which were extended is dangerous
3840 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3842 OpcodeCast lcast = left as OpcodeCast;
3843 if (lcast != null) {
3844 if (IsUnsigned (lcast.UnderlyingType))
3848 OpcodeCast rcast = right as OpcodeCast;
3849 if (rcast != null) {
3850 if (IsUnsigned (rcast.UnderlyingType))
3854 if (lcast == null && rcast == null)
3857 // FIXME: consider constants
3859 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3860 ec.Report.Warning (675, 3, loc,
3861 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3862 ltype.GetSignatureForError ());
3865 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3867 return new PredefinedOperator[] {
3869 // Pointer arithmetic:
3871 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3872 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3873 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3874 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3876 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3877 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3878 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3879 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3882 // T* operator + (int y, T* x);
3883 // T* operator + (uint y, T *x);
3884 // T* operator + (long y, T *x);
3885 // T* operator + (ulong y, T *x);
3887 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3888 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3889 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3890 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3893 // long operator - (T* x, T *y)
3895 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3899 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3901 TypeSpec bool_type = types.Bool;
3904 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3905 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3906 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3907 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3908 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3909 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3910 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3912 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3913 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3914 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3915 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3916 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3917 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3918 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3920 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3921 // Remaining string operators are in lifted tables
3923 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3925 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3926 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3927 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3931 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3933 var types = module.Compiler.BuiltinTypes;
3936 // Not strictly lifted but need to be in second group otherwise expressions like
3937 // int + null would resolve to +(object, string) instead of +(int?, int?)
3939 var string_operators = new [] {
3940 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3941 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3944 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3945 if (nullable == null)
3946 return string_operators;
3948 var bool_type = types.Bool;
3950 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3951 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3952 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3953 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3954 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3955 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3956 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3957 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3960 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3961 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3962 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3963 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3964 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3965 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3966 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3968 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3969 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3970 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3971 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3972 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3973 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3974 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3976 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3978 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3979 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3980 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3982 string_operators [0],
3983 string_operators [1]
3987 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3989 TypeSpec bool_type = types.Bool;
3992 new PredefinedEqualityOperator (types.String, bool_type),
3993 new PredefinedEqualityOperator (types.Delegate, bool_type),
3994 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3995 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3996 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3997 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3998 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3999 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4000 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4001 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4005 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4007 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4009 if (nullable == null)
4010 return new PredefinedOperator [0];
4012 var types = module.Compiler.BuiltinTypes;
4013 var bool_type = types.Bool;
4014 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4015 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4016 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4017 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4018 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4019 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4020 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4021 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4024 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4025 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4026 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4027 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4028 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4029 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4030 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4031 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4036 // 7.2.6.2 Binary numeric promotions
4038 bool DoBinaryOperatorPromotion (ResolveContext rc)
4040 TypeSpec ltype = left.Type;
4041 if (ltype.IsNullableType) {
4042 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4046 // This is numeric promotion code only
4048 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4051 TypeSpec rtype = right.Type;
4052 if (rtype.IsNullableType) {
4053 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4056 var lb = ltype.BuiltinType;
4057 var rb = rtype.BuiltinType;
4061 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4062 type = rc.BuiltinTypes.Decimal;
4063 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4064 type = rc.BuiltinTypes.Double;
4065 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4066 type = rc.BuiltinTypes.Float;
4067 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4068 type = rc.BuiltinTypes.ULong;
4070 if (IsSignedType (lb)) {
4071 expr = ConvertSignedConstant (left, type);
4075 } else if (IsSignedType (rb)) {
4076 expr = ConvertSignedConstant (right, type);
4082 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4083 type = rc.BuiltinTypes.Long;
4084 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4085 type = rc.BuiltinTypes.UInt;
4087 if (IsSignedType (lb)) {
4088 expr = ConvertSignedConstant (left, type);
4090 type = rc.BuiltinTypes.Long;
4091 } else if (IsSignedType (rb)) {
4092 expr = ConvertSignedConstant (right, type);
4094 type = rc.BuiltinTypes.Long;
4097 type = rc.BuiltinTypes.Int;
4100 if (ltype != type) {
4101 expr = PromoteExpression (rc, left, type);
4108 if (rtype != type) {
4109 expr = PromoteExpression (rc, right, type);
4119 static bool IsSignedType (BuiltinTypeSpec.Type type)
4122 case BuiltinTypeSpec.Type.Int:
4123 case BuiltinTypeSpec.Type.Short:
4124 case BuiltinTypeSpec.Type.SByte:
4125 case BuiltinTypeSpec.Type.Long:
4132 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4134 var c = expr as Constant;
4138 return c.ConvertImplicitly (type);
4141 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4143 if (expr.Type.IsNullableType) {
4144 return Convert.ImplicitConversionStandard (rc, expr,
4145 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4148 var c = expr as Constant;
4150 return c.ConvertImplicitly (type);
4152 return Convert.ImplicitNumericConversion (expr, type);
4155 protected override Expression DoResolve (ResolveContext ec)
4160 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4161 left = ((ParenthesizedExpression) left).Expr;
4162 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4166 if (left.eclass == ExprClass.Type) {
4167 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4171 left = left.Resolve (ec);
4176 right = right.Resolve (ec);
4180 Constant lc = left as Constant;
4181 Constant rc = right as Constant;
4183 // The conversion rules are ignored in enum context but why
4184 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4185 lc = EnumLiftUp (ec, lc, rc);
4187 rc = EnumLiftUp (ec, rc, lc);
4190 if (rc != null && lc != null) {
4191 int prev_e = ec.Report.Errors;
4192 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4193 if (e != null || ec.Report.Errors != prev_e)
4197 // Comparison warnings
4198 if ((oper & Operator.ComparisonMask) != 0) {
4199 if (left.Equals (right)) {
4200 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4202 CheckOutOfRangeComparison (ec, lc, right.Type);
4203 CheckOutOfRangeComparison (ec, rc, left.Type);
4206 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4207 return DoResolveDynamic (ec);
4209 return DoResolveCore (ec, left, right);
4212 Expression DoResolveDynamic (ResolveContext rc)
4215 var rt = right.Type;
4216 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4217 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4218 Error_OperatorCannotBeApplied (rc, left, right);
4225 // Special handling for logical boolean operators which require rhs not to be
4226 // evaluated based on lhs value
4228 if ((oper & Operator.LogicalMask) != 0) {
4229 Expression cond_left, cond_right, expr;
4231 args = new Arguments (2);
4233 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4234 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4236 var cond_args = new Arguments (1);
4237 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4240 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4241 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4243 left = temp.CreateReferenceExpression (rc, loc);
4244 if (oper == Operator.LogicalAnd) {
4245 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4248 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4252 args.Add (new Argument (left));
4253 args.Add (new Argument (right));
4254 cond_right = new DynamicExpressionStatement (this, args, loc);
4256 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4258 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4259 rc.Report.Error (7083, left.Location,
4260 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4261 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4265 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4266 args.Add (new Argument (right));
4267 right = new DynamicExpressionStatement (this, args, loc);
4270 // bool && dynamic => (temp = left) ? temp && right : temp;
4271 // bool || dynamic => (temp = left) ? temp : temp || right;
4273 if (oper == Operator.LogicalAnd) {
4275 cond_right = temp.CreateReferenceExpression (rc, loc);
4277 cond_left = temp.CreateReferenceExpression (rc, loc);
4281 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4284 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4287 args = new Arguments (2);
4288 args.Add (new Argument (left));
4289 args.Add (new Argument (right));
4290 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4293 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4295 Expression expr = ResolveOperator (ec);
4297 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4299 if (left == null || right == null)
4300 throw new InternalErrorException ("Invalid conversion");
4302 if (oper == Operator.BitwiseOr)
4303 CheckBitwiseOrOnSignExtended (ec);
4308 public override SLE.Expression MakeExpression (BuilderContext ctx)
4310 return MakeExpression (ctx, left, right);
4313 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4315 var le = left.MakeExpression (ctx);
4316 var re = right.MakeExpression (ctx);
4317 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4320 case Operator.Addition:
4321 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4322 case Operator.BitwiseAnd:
4323 return SLE.Expression.And (le, re);
4324 case Operator.BitwiseOr:
4325 return SLE.Expression.Or (le, re);
4326 case Operator.Division:
4327 return SLE.Expression.Divide (le, re);
4328 case Operator.Equality:
4329 return SLE.Expression.Equal (le, re);
4330 case Operator.ExclusiveOr:
4331 return SLE.Expression.ExclusiveOr (le, re);
4332 case Operator.GreaterThan:
4333 return SLE.Expression.GreaterThan (le, re);
4334 case Operator.GreaterThanOrEqual:
4335 return SLE.Expression.GreaterThanOrEqual (le, re);
4336 case Operator.Inequality:
4337 return SLE.Expression.NotEqual (le, re);
4338 case Operator.LeftShift:
4339 return SLE.Expression.LeftShift (le, re);
4340 case Operator.LessThan:
4341 return SLE.Expression.LessThan (le, re);
4342 case Operator.LessThanOrEqual:
4343 return SLE.Expression.LessThanOrEqual (le, re);
4344 case Operator.LogicalAnd:
4345 return SLE.Expression.AndAlso (le, re);
4346 case Operator.LogicalOr:
4347 return SLE.Expression.OrElse (le, re);
4348 case Operator.Modulus:
4349 return SLE.Expression.Modulo (le, re);
4350 case Operator.Multiply:
4351 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4352 case Operator.RightShift:
4353 return SLE.Expression.RightShift (le, re);
4354 case Operator.Subtraction:
4355 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4357 throw new NotImplementedException (oper.ToString ());
4362 // D operator + (D x, D y)
4363 // D operator - (D x, D y)
4365 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4367 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4369 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4370 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4375 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4376 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4386 MethodSpec method = null;
4387 Arguments args = new Arguments (2);
4388 args.Add (new Argument (left));
4389 args.Add (new Argument (right));
4391 if (oper == Operator.Addition) {
4392 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4393 } else if (oper == Operator.Subtraction) {
4394 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4398 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4400 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4401 return new ClassCast (expr, l);
4405 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4407 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4410 // bool operator == (E x, E y);
4411 // bool operator != (E x, E y);
4412 // bool operator < (E x, E y);
4413 // bool operator > (E x, E y);
4414 // bool operator <= (E x, E y);
4415 // bool operator >= (E x, E y);
4417 // E operator & (E x, E y);
4418 // E operator | (E x, E y);
4419 // E operator ^ (E x, E y);
4422 if ((oper & Operator.ComparisonMask) != 0) {
4423 type = rc.BuiltinTypes.Bool;
4429 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4435 if (ltype == rtype) {
4439 var lifted = new Nullable.LiftedBinaryOperator (this);
4441 lifted.Right = right;
4442 return lifted.Resolve (rc);
4445 if (renum && !ltype.IsNullableType) {
4446 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4451 } else if (lenum && !rtype.IsNullableType) {
4452 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4460 // Now try lifted version of predefined operator
4462 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4463 if (nullable_type != null) {
4464 if (renum && !ltype.IsNullableType) {
4465 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4467 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4470 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4473 if ((oper & Operator.BitwiseMask) != 0)
4477 if ((oper & Operator.BitwiseMask) != 0)
4478 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4480 return CreateLiftedValueTypeResult (rc, rtype);
4484 var lifted = new Nullable.LiftedBinaryOperator (this);
4486 lifted.Right = right;
4487 return lifted.Resolve (rc);
4489 } else if (lenum && !rtype.IsNullableType) {
4490 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4492 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4495 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4498 if ((oper & Operator.BitwiseMask) != 0)
4502 if ((oper & Operator.BitwiseMask) != 0)
4503 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4505 return CreateLiftedValueTypeResult (rc, ltype);
4509 var lifted = new Nullable.LiftedBinaryOperator (this);
4511 lifted.Right = expr;
4512 return lifted.Resolve (rc);
4514 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4515 Nullable.Unwrap unwrap = null;
4516 if (left.IsNull || right.IsNull) {
4517 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4518 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4520 if ((oper & Operator.RelationalMask) != 0)
4521 return CreateLiftedValueTypeResult (rc, rtype);
4523 if ((oper & Operator.BitwiseMask) != 0)
4524 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4527 return CreateLiftedValueTypeResult (rc, left.Type);
4529 // Equality operators are valid between E? and null
4531 unwrap = new Nullable.Unwrap (right);
4533 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4539 var lifted = new Nullable.LiftedBinaryOperator (this);
4541 lifted.Right = right;
4542 lifted.UnwrapRight = unwrap;
4543 return lifted.Resolve (rc);
4545 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4546 Nullable.Unwrap unwrap = null;
4547 if (right.IsNull || left.IsNull) {
4548 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4549 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4551 if ((oper & Operator.RelationalMask) != 0)
4552 return CreateLiftedValueTypeResult (rc, ltype);
4554 if ((oper & Operator.BitwiseMask) != 0)
4555 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4558 return CreateLiftedValueTypeResult (rc, right.Type);
4560 // Equality operators are valid between E? and null
4562 unwrap = new Nullable.Unwrap (left);
4564 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4570 var lifted = new Nullable.LiftedBinaryOperator (this);
4572 lifted.UnwrapLeft = unwrap;
4573 lifted.Right = expr;
4574 return lifted.Resolve (rc);
4582 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4584 TypeSpec underlying_type;
4585 if (expr.Type.IsNullableType) {
4586 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4588 underlying_type = EnumSpec.GetUnderlyingType (nt);
4590 underlying_type = nt;
4591 } else if (expr.Type.IsEnum) {
4592 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4594 underlying_type = expr.Type;
4597 switch (underlying_type.BuiltinType) {
4598 case BuiltinTypeSpec.Type.SByte:
4599 case BuiltinTypeSpec.Type.Byte:
4600 case BuiltinTypeSpec.Type.Short:
4601 case BuiltinTypeSpec.Type.UShort:
4602 underlying_type = rc.BuiltinTypes.Int;
4606 if (expr.Type.IsNullableType || liftType)
4607 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4609 if (expr.Type == underlying_type)
4612 return EmptyCast.Create (expr, underlying_type);
4615 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4618 // U operator - (E e, E f)
4619 // E operator - (E e, U x) // Internal decomposition operator
4620 // E operator - (U x, E e) // Internal decomposition operator
4622 // E operator + (E e, U x)
4623 // E operator + (U x, E e)
4632 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4638 if (!enum_type.IsNullableType) {
4639 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4641 if (oper == Operator.Subtraction)
4642 expr = ConvertEnumSubtractionResult (rc, expr);
4644 expr = ConvertEnumAdditionalResult (expr, enum_type);
4646 enum_conversion = GetEnumResultCast (expr.Type);
4651 var nullable = rc.Module.PredefinedTypes.Nullable;
4654 // Don't try nullable version when nullable type is undefined
4656 if (!nullable.IsDefined)
4659 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4662 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4664 if (oper == Operator.Subtraction)
4665 expr = ConvertEnumSubtractionResult (rc, expr);
4667 expr = ConvertEnumAdditionalResult (expr, enum_type);
4669 enum_conversion = GetEnumResultCast (expr.Type);
4675 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4677 return EmptyCast.Create (expr, enumType);
4680 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4683 // Enumeration subtraction has different result type based on
4686 TypeSpec result_type;
4687 if (left.Type == right.Type) {
4688 var c = right as EnumConstant;
4689 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4691 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4692 // E which is not what expressions E - 1 or 0 - E return
4694 result_type = left.Type;
4696 result_type = left.Type.IsNullableType ?
4697 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4698 EnumSpec.GetUnderlyingType (left.Type);
4701 if (IsEnumOrNullableEnum (left.Type)) {
4702 result_type = left.Type;
4704 result_type = right.Type;
4707 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4708 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4711 return EmptyCast.Create (expr, result_type);
4714 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4716 if (type.IsNullableType)
4717 type = Nullable.NullableInfo.GetUnderlyingType (type);
4720 type = EnumSpec.GetUnderlyingType (type);
4722 switch (type.BuiltinType) {
4723 case BuiltinTypeSpec.Type.SByte:
4724 return ConvCast.Mode.I4_I1;
4725 case BuiltinTypeSpec.Type.Byte:
4726 return ConvCast.Mode.I4_U1;
4727 case BuiltinTypeSpec.Type.Short:
4728 return ConvCast.Mode.I4_I2;
4729 case BuiltinTypeSpec.Type.UShort:
4730 return ConvCast.Mode.I4_U2;
4737 // Equality operators rules
4739 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4742 type = ec.BuiltinTypes.Bool;
4743 bool no_arg_conv = false;
4745 if (!primitives_only) {
4748 // a, Both operands are reference-type values or the value null
4749 // b, One operand is a value of type T where T is a type-parameter and
4750 // the other operand is the value null. Furthermore T does not have the
4751 // value type constraint
4753 // LAMESPEC: Very confusing details in the specification, basically any
4754 // reference like type-parameter is allowed
4756 var tparam_l = l as TypeParameterSpec;
4757 var tparam_r = r as TypeParameterSpec;
4758 if (tparam_l != null) {
4759 if (right is NullLiteral) {
4760 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4763 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4767 if (!tparam_l.IsReferenceType)
4770 l = tparam_l.GetEffectiveBase ();
4771 left = new BoxedCast (left, l);
4772 } else if (left is NullLiteral && tparam_r == null) {
4773 if (TypeSpec.IsReferenceType (r))
4776 if (r.Kind == MemberKind.InternalCompilerType)
4780 if (tparam_r != null) {
4781 if (left is NullLiteral) {
4782 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4785 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4789 if (!tparam_r.IsReferenceType)
4792 r = tparam_r.GetEffectiveBase ();
4793 right = new BoxedCast (right, r);
4794 } else if (right is NullLiteral) {
4795 if (TypeSpec.IsReferenceType (l))
4798 if (l.Kind == MemberKind.InternalCompilerType)
4803 // LAMESPEC: method groups can be compared when they convert to other side delegate
4806 if (right.eclass == ExprClass.MethodGroup) {
4807 result = Convert.ImplicitConversion (ec, right, l, loc);
4813 } else if (r.IsDelegate && l != r) {
4816 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4817 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4824 no_arg_conv = l == r && !l.IsStruct;
4829 // bool operator != (string a, string b)
4830 // bool operator == (string a, string b)
4832 // bool operator != (Delegate a, Delegate b)
4833 // bool operator == (Delegate a, Delegate b)
4835 // bool operator != (bool a, bool b)
4836 // bool operator == (bool a, bool b)
4838 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4839 // they implement an implicit conversion to any of types above. This does
4840 // not apply when both operands are of same reference type
4842 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4843 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4848 // Now try lifted version of predefined operators
4850 if (no_arg_conv && !l.IsNullableType) {
4852 // Optimizes cases which won't match
4855 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4861 // The == and != operators permit one operand to be a value of a nullable
4862 // type and the other to be the null literal, even if no predefined or user-defined
4863 // operator (in unlifted or lifted form) exists for the operation.
4865 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4866 var lifted = new Nullable.LiftedBinaryOperator (this);
4868 lifted.Right = right;
4869 return lifted.Resolve (ec);
4874 // bool operator != (object a, object b)
4875 // bool operator == (object a, object b)
4877 // An explicit reference conversion exists from the
4878 // type of either operand to the type of the other operand.
4881 // Optimize common path
4883 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4886 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4887 !Convert.ExplicitReferenceConversionExists (r, l))
4890 // Reject allowed explicit conversions like int->object
4891 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4894 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4895 ec.Report.Warning (253, 2, loc,
4896 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4897 l.GetSignatureForError ());
4899 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4900 ec.Report.Warning (252, 2, loc,
4901 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4902 r.GetSignatureForError ());
4908 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4911 // bool operator == (void* x, void* y);
4912 // bool operator != (void* x, void* y);
4913 // bool operator < (void* x, void* y);
4914 // bool operator > (void* x, void* y);
4915 // bool operator <= (void* x, void* y);
4916 // bool operator >= (void* x, void* y);
4918 if ((oper & Operator.ComparisonMask) != 0) {
4921 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4928 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4934 type = ec.BuiltinTypes.Bool;
4938 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4942 // Build-in operators method overloading
4944 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4946 PredefinedOperator best_operator = null;
4947 TypeSpec l = left.Type;
4948 TypeSpec r = right.Type;
4949 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4951 foreach (PredefinedOperator po in operators) {
4952 if ((po.OperatorsMask & oper_mask) == 0)
4955 if (primitives_only) {
4956 if (!po.IsPrimitiveApplicable (l, r))
4959 if (!po.IsApplicable (ec, left, right))
4963 if (best_operator == null) {
4965 if (primitives_only)
4971 best_operator = po.ResolveBetterOperator (ec, best_operator);
4973 if (best_operator == null) {
4974 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4975 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4982 if (best_operator == null)
4985 return best_operator.ConvertResult (ec, this);
4989 // Optimize & constant expressions with 0 value
4991 Expression OptimizeAndOperation (Expression expr)
4993 Constant rc = right as Constant;
4994 Constant lc = left as Constant;
4995 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4997 // The result is a constant with side-effect
4999 Constant side_effect = rc == null ?
5000 new SideEffectConstant (lc, right, loc) :
5001 new SideEffectConstant (rc, left, loc);
5003 return ReducedExpression.Create (side_effect, expr);
5010 // Value types can be compared with the null literal because of the lifting
5011 // language rules. However the result is always true or false.
5013 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5015 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5016 type = rc.BuiltinTypes.Bool;
5020 // FIXME: Handle side effect constants
5021 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5023 if ((Oper & Operator.EqualityMask) != 0) {
5024 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5025 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5027 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5028 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5035 // Performs user-operator overloading
5037 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5039 Expression oper_expr;
5041 var op = ConvertBinaryToUserOperator (oper);
5043 if (l.IsNullableType)
5044 l = Nullable.NullableInfo.GetUnderlyingType (l);
5046 if (r.IsNullableType)
5047 r = Nullable.NullableInfo.GetUnderlyingType (r);
5049 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5050 IList<MemberSpec> right_operators = null;
5053 right_operators = MemberCache.GetUserOperator (r, op, false);
5054 if (right_operators == null && left_operators == null)
5056 } else if (left_operators == null) {
5060 Arguments args = new Arguments (2);
5061 Argument larg = new Argument (left);
5063 Argument rarg = new Argument (right);
5067 // User-defined operator implementations always take precedence
5068 // over predefined operator implementations
5070 if (left_operators != null && right_operators != null) {
5071 left_operators = CombineUserOperators (left_operators, right_operators);
5072 } else if (right_operators != null) {
5073 left_operators = right_operators;
5076 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5077 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5079 var res = new OverloadResolver (left_operators, restr, loc);
5081 var oper_method = res.ResolveOperator (rc, ref args);
5082 if (oper_method == null) {
5084 // Logical && and || cannot be lifted
5086 if ((oper & Operator.LogicalMask) != 0)
5090 // Apply lifted user operators only for liftable types. Implicit conversion
5091 // to nullable types is not allowed
5093 if (!IsLiftedOperatorApplicable ())
5096 // TODO: Cache the result in module container
5097 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5098 if (lifted_methods == null)
5101 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5103 oper_method = res.ResolveOperator (rc, ref args);
5104 if (oper_method == null)
5107 MethodSpec best_original = null;
5108 foreach (MethodSpec ms in left_operators) {
5109 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5115 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5117 // Expression trees use lifted notation in this case
5119 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5120 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5123 var ptypes = best_original.Parameters.Types;
5125 if (left.IsNull || right.IsNull) {
5127 // The lifted operator produces a null value if one or both operands are null
5129 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5130 type = oper_method.ReturnType;
5131 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5135 // The lifted operator produces the value false if one or both operands are null for
5136 // relational operators.
5138 if ((oper & Operator.RelationalMask) != 0) {
5140 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5141 // because return type is actually bool
5143 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5146 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5147 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5151 type = oper_method.ReturnType;
5152 var lifted = new Nullable.LiftedBinaryOperator (this);
5153 lifted.UserOperator = best_original;
5155 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5156 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5159 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5160 lifted.UnwrapRight = new Nullable.Unwrap (right);
5163 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5164 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5166 return lifted.Resolve (rc);
5169 if ((oper & Operator.LogicalMask) != 0) {
5170 // TODO: CreateExpressionTree is allocated every time
5171 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5172 oper == Operator.LogicalAnd, loc).Resolve (rc);
5174 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5177 this.left = larg.Expr;
5178 this.right = rarg.Expr;
5183 bool IsLiftedOperatorApplicable ()
5185 if (left.Type.IsNullableType) {
5186 if ((oper & Operator.EqualityMask) != 0)
5187 return !right.IsNull;
5192 if (right.Type.IsNullableType) {
5193 if ((oper & Operator.EqualityMask) != 0)
5194 return !left.IsNull;
5199 if (TypeSpec.IsValueType (left.Type))
5200 return right.IsNull;
5202 if (TypeSpec.IsValueType (right.Type))
5208 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5210 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5211 if (nullable_type == null)
5215 // Lifted operators permit predefined and user-defined operators that operate
5216 // on non-nullable value types to also be used with nullable forms of those types.
5217 // Lifted operators are constructed from predefined and user-defined operators
5218 // that meet certain requirements
5220 List<MemberSpec> lifted = null;
5221 foreach (MethodSpec oper in operators) {
5223 if ((Oper & Operator.ComparisonMask) != 0) {
5225 // Result type must be of type bool for lifted comparison operators
5227 rt = oper.ReturnType;
5228 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5231 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5237 var ptypes = oper.Parameters.Types;
5238 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5242 // LAMESPEC: I am not sure why but for equality operators to be lifted
5243 // both types have to match
5245 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5249 lifted = new List<MemberSpec> ();
5252 // The lifted form is constructed by adding a single ? modifier to each operand and
5253 // result type except for comparison operators where return type is bool
5256 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5258 var parameters = ParametersCompiled.CreateFullyResolved (
5259 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5260 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5262 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5263 rt, parameters, oper.Modifiers);
5265 lifted.Add (lifted_op);
5272 // Merge two sets of user operators into one, they are mostly distinguish
5273 // except when they share base type and it contains an operator
5275 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5277 var combined = new List<MemberSpec> (left.Count + right.Count);
5278 combined.AddRange (left);
5279 foreach (var r in right) {
5281 foreach (var l in left) {
5282 if (l.DeclaringType == r.DeclaringType) {
5295 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5297 if (c is IntegralConstant || c is CharConstant) {
5299 c.ConvertExplicitly (true, type);
5300 } catch (OverflowException) {
5301 ec.Report.Warning (652, 2, loc,
5302 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5303 type.GetSignatureForError ());
5309 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5310 /// context of a conditional bool expression. This function will return
5311 /// false if it is was possible to use EmitBranchable, or true if it was.
5313 /// The expression's code is generated, and we will generate a branch to `target'
5314 /// if the resulting expression value is equal to isTrue
5316 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5318 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5319 left = left.EmitToField (ec);
5321 if ((oper & Operator.LogicalMask) == 0) {
5322 right = right.EmitToField (ec);
5327 // This is more complicated than it looks, but its just to avoid
5328 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5329 // but on top of that we want for == and != to use a special path
5330 // if we are comparing against null
5332 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5333 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5336 // put the constant on the rhs, for simplicity
5338 if (left is Constant) {
5339 Expression swap = right;
5345 // brtrue/brfalse works with native int only
5347 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5348 left.EmitBranchable (ec, target, my_on_true);
5351 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5352 // right is a boolean, and it's not 'false' => it is 'true'
5353 left.EmitBranchable (ec, target, !my_on_true);
5357 } else if (oper == Operator.LogicalAnd) {
5360 Label tests_end = ec.DefineLabel ();
5362 left.EmitBranchable (ec, tests_end, false);
5363 right.EmitBranchable (ec, target, true);
5364 ec.MarkLabel (tests_end);
5367 // This optimizes code like this
5368 // if (true && i > 4)
5370 if (!(left is Constant))
5371 left.EmitBranchable (ec, target, false);
5373 if (!(right is Constant))
5374 right.EmitBranchable (ec, target, false);
5379 } else if (oper == Operator.LogicalOr){
5381 left.EmitBranchable (ec, target, true);
5382 right.EmitBranchable (ec, target, true);
5385 Label tests_end = ec.DefineLabel ();
5386 left.EmitBranchable (ec, tests_end, true);
5387 right.EmitBranchable (ec, target, false);
5388 ec.MarkLabel (tests_end);
5393 } else if ((oper & Operator.ComparisonMask) == 0) {
5394 base.EmitBranchable (ec, target, on_true);
5401 TypeSpec t = left.Type;
5402 bool is_float = IsFloat (t);
5403 bool is_unsigned = is_float || IsUnsigned (t);
5406 case Operator.Equality:
5408 ec.Emit (OpCodes.Beq, target);
5410 ec.Emit (OpCodes.Bne_Un, target);
5413 case Operator.Inequality:
5415 ec.Emit (OpCodes.Bne_Un, target);
5417 ec.Emit (OpCodes.Beq, target);
5420 case Operator.LessThan:
5422 if (is_unsigned && !is_float)
5423 ec.Emit (OpCodes.Blt_Un, target);
5425 ec.Emit (OpCodes.Blt, target);
5428 ec.Emit (OpCodes.Bge_Un, target);
5430 ec.Emit (OpCodes.Bge, target);
5433 case Operator.GreaterThan:
5435 if (is_unsigned && !is_float)
5436 ec.Emit (OpCodes.Bgt_Un, target);
5438 ec.Emit (OpCodes.Bgt, target);
5441 ec.Emit (OpCodes.Ble_Un, target);
5443 ec.Emit (OpCodes.Ble, target);
5446 case Operator.LessThanOrEqual:
5448 if (is_unsigned && !is_float)
5449 ec.Emit (OpCodes.Ble_Un, target);
5451 ec.Emit (OpCodes.Ble, target);
5454 ec.Emit (OpCodes.Bgt_Un, target);
5456 ec.Emit (OpCodes.Bgt, target);
5460 case Operator.GreaterThanOrEqual:
5462 if (is_unsigned && !is_float)
5463 ec.Emit (OpCodes.Bge_Un, target);
5465 ec.Emit (OpCodes.Bge, target);
5468 ec.Emit (OpCodes.Blt_Un, target);
5470 ec.Emit (OpCodes.Blt, target);
5473 throw new InternalErrorException (oper.ToString ());
5477 public override void Emit (EmitContext ec)
5479 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5480 left = left.EmitToField (ec);
5482 if ((oper & Operator.LogicalMask) == 0) {
5483 right = right.EmitToField (ec);
5488 // Handle short-circuit operators differently
5491 if ((oper & Operator.LogicalMask) != 0) {
5492 Label load_result = ec.DefineLabel ();
5493 Label end = ec.DefineLabel ();
5495 bool is_or = oper == Operator.LogicalOr;
5496 left.EmitBranchable (ec, load_result, is_or);
5498 ec.Emit (OpCodes.Br_S, end);
5500 ec.MarkLabel (load_result);
5501 ec.EmitInt (is_or ? 1 : 0);
5507 // Optimize zero-based operations which cannot be optimized at expression level
5509 if (oper == Operator.Subtraction) {
5510 var lc = left as IntegralConstant;
5511 if (lc != null && lc.IsDefaultValue) {
5513 ec.Emit (OpCodes.Neg);
5518 EmitOperator (ec, left, right);
5521 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5526 EmitOperatorOpcode (ec, oper, left.Type, right);
5529 // Emit result enumerable conversion this way because it's quite complicated get it
5530 // to resolved tree because expression tree cannot see it.
5532 if (enum_conversion != 0)
5533 ConvCast.Emit (ec, enum_conversion);
5536 public override void EmitSideEffect (EmitContext ec)
5538 if ((oper & Operator.LogicalMask) != 0 ||
5539 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5540 base.EmitSideEffect (ec);
5542 left.EmitSideEffect (ec);
5543 right.EmitSideEffect (ec);
5547 public override Expression EmitToField (EmitContext ec)
5549 if ((oper & Operator.LogicalMask) == 0) {
5550 var await_expr = left as Await;
5551 if (await_expr != null && right.IsSideEffectFree) {
5552 await_expr.Statement.EmitPrologue (ec);
5553 left = await_expr.Statement.GetResultExpression (ec);
5557 await_expr = right as Await;
5558 if (await_expr != null && left.IsSideEffectFree) {
5559 await_expr.Statement.EmitPrologue (ec);
5560 right = await_expr.Statement.GetResultExpression (ec);
5565 return base.EmitToField (ec);
5568 protected override void CloneTo (CloneContext clonectx, Expression t)
5570 Binary target = (Binary) t;
5572 target.left = left.Clone (clonectx);
5573 target.right = right.Clone (clonectx);
5576 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5578 Arguments binder_args = new Arguments (4);
5580 MemberAccess sle = new MemberAccess (new MemberAccess (
5581 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5583 CSharpBinderFlags flags = 0;
5584 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5585 flags = CSharpBinderFlags.CheckedContext;
5587 if ((oper & Operator.LogicalMask) != 0)
5588 flags |= CSharpBinderFlags.BinaryOperationLogical;
5590 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5591 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5592 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5593 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5595 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5598 public override Expression CreateExpressionTree (ResolveContext ec)
5600 return CreateExpressionTree (ec, null);
5603 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5606 bool lift_arg = false;
5609 case Operator.Addition:
5610 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5611 method_name = "AddChecked";
5613 method_name = "Add";
5615 case Operator.BitwiseAnd:
5616 method_name = "And";
5618 case Operator.BitwiseOr:
5621 case Operator.Division:
5622 method_name = "Divide";
5624 case Operator.Equality:
5625 method_name = "Equal";
5628 case Operator.ExclusiveOr:
5629 method_name = "ExclusiveOr";
5631 case Operator.GreaterThan:
5632 method_name = "GreaterThan";
5635 case Operator.GreaterThanOrEqual:
5636 method_name = "GreaterThanOrEqual";
5639 case Operator.Inequality:
5640 method_name = "NotEqual";
5643 case Operator.LeftShift:
5644 method_name = "LeftShift";
5646 case Operator.LessThan:
5647 method_name = "LessThan";
5650 case Operator.LessThanOrEqual:
5651 method_name = "LessThanOrEqual";
5654 case Operator.LogicalAnd:
5655 method_name = "AndAlso";
5657 case Operator.LogicalOr:
5658 method_name = "OrElse";
5660 case Operator.Modulus:
5661 method_name = "Modulo";
5663 case Operator.Multiply:
5664 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5665 method_name = "MultiplyChecked";
5667 method_name = "Multiply";
5669 case Operator.RightShift:
5670 method_name = "RightShift";
5672 case Operator.Subtraction:
5673 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5674 method_name = "SubtractChecked";
5676 method_name = "Subtract";
5680 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5683 Arguments args = new Arguments (2);
5684 args.Add (new Argument (left.CreateExpressionTree (ec)));
5685 args.Add (new Argument (right.CreateExpressionTree (ec)));
5686 if (method != null) {
5688 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5690 args.Add (new Argument (method));
5693 return CreateExpressionFactoryCall (ec, method_name, args);
5696 public override object Accept (StructuralVisitor visitor)
5698 return visitor.Visit (this);
5704 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5705 // b, c, d... may be strings or objects.
5707 public class StringConcat : Expression
5709 Arguments arguments;
5711 StringConcat (Location loc)
5714 arguments = new Arguments (2);
5717 public override bool ContainsEmitWithAwait ()
5719 return arguments.ContainsEmitWithAwait ();
5722 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5724 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5725 throw new ArgumentException ();
5727 var s = new StringConcat (loc);
5728 s.type = rc.BuiltinTypes.String;
5729 s.eclass = ExprClass.Value;
5731 s.Append (rc, left);
5732 s.Append (rc, right);
5736 public override Expression CreateExpressionTree (ResolveContext ec)
5738 Argument arg = arguments [0];
5739 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5743 // Creates nested calls tree from an array of arguments used for IL emit
5745 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5747 Arguments concat_args = new Arguments (2);
5748 Arguments add_args = new Arguments (3);
5750 concat_args.Add (left);
5751 add_args.Add (new Argument (left_etree));
5753 concat_args.Add (arguments [pos]);
5754 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5756 var methods = GetConcatMethodCandidates ();
5757 if (methods == null)
5760 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5761 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5765 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5767 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5768 if (++pos == arguments.Count)
5771 left = new Argument (new EmptyExpression (method.ReturnType));
5772 return CreateExpressionAddCall (ec, left, expr, pos);
5775 protected override Expression DoResolve (ResolveContext ec)
5780 void Append (ResolveContext rc, Expression operand)
5785 StringConstant sc = operand as StringConstant;
5787 if (arguments.Count != 0) {
5788 Argument last_argument = arguments [arguments.Count - 1];
5789 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5790 if (last_expr_constant != null) {
5791 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5797 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5799 StringConcat concat_oper = operand as StringConcat;
5800 if (concat_oper != null) {
5801 arguments.AddRange (concat_oper.arguments);
5806 arguments.Add (new Argument (operand));
5809 IList<MemberSpec> GetConcatMethodCandidates ()
5811 return MemberCache.FindMembers (type, "Concat", true);
5814 public override void Emit (EmitContext ec)
5816 // Optimize by removing any extra null arguments, they are no-op
5817 for (int i = 0; i < arguments.Count; ++i) {
5818 if (arguments[i].Expr is NullConstant)
5819 arguments.RemoveAt (i--);
5822 var members = GetConcatMethodCandidates ();
5823 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5824 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5825 if (method != null) {
5826 var call = new CallEmitter ();
5827 call.EmitPredefined (ec, method, arguments, false);
5831 public override void FlowAnalysis (FlowAnalysisContext fc)
5833 arguments.FlowAnalysis (fc);
5836 public override SLE.Expression MakeExpression (BuilderContext ctx)
5838 if (arguments.Count != 2)
5839 throw new NotImplementedException ("arguments.Count != 2");
5841 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5842 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5847 // User-defined conditional logical operator
5849 public class ConditionalLogicalOperator : UserOperatorCall
5851 readonly bool is_and;
5852 Expression oper_expr;
5854 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5855 : base (oper, arguments, expr_tree, loc)
5857 this.is_and = is_and;
5858 eclass = ExprClass.Unresolved;
5861 protected override Expression DoResolve (ResolveContext ec)
5863 AParametersCollection pd = oper.Parameters;
5864 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5865 ec.Report.Error (217, loc,
5866 "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",
5867 oper.GetSignatureForError ());
5871 Expression left_dup = new EmptyExpression (type);
5872 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5873 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5874 if (op_true == null || op_false == null) {
5875 ec.Report.Error (218, loc,
5876 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5877 type.GetSignatureForError (), oper.GetSignatureForError ());
5881 oper_expr = is_and ? op_false : op_true;
5882 eclass = ExprClass.Value;
5886 public override void Emit (EmitContext ec)
5888 Label end_target = ec.DefineLabel ();
5891 // Emit and duplicate left argument
5893 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5894 if (right_contains_await) {
5895 arguments[0] = arguments[0].EmitToField (ec, false);
5896 arguments[0].Expr.Emit (ec);
5898 arguments[0].Expr.Emit (ec);
5899 ec.Emit (OpCodes.Dup);
5900 arguments.RemoveAt (0);
5903 oper_expr.EmitBranchable (ec, end_target, true);
5907 if (right_contains_await) {
5909 // Special handling when right expression contains await and left argument
5910 // could not be left on stack before logical branch
5912 Label skip_left_load = ec.DefineLabel ();
5913 ec.Emit (OpCodes.Br_S, skip_left_load);
5914 ec.MarkLabel (end_target);
5915 arguments[0].Expr.Emit (ec);
5916 ec.MarkLabel (skip_left_load);
5918 ec.MarkLabel (end_target);
5923 public class PointerArithmetic : Expression {
5924 Expression left, right;
5925 readonly Binary.Operator op;
5928 // We assume that `l' is always a pointer
5930 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5939 public override bool ContainsEmitWithAwait ()
5941 throw new NotImplementedException ();
5944 public override Expression CreateExpressionTree (ResolveContext ec)
5946 Error_PointerInsideExpressionTree (ec);
5950 protected override Expression DoResolve (ResolveContext ec)
5952 eclass = ExprClass.Variable;
5954 var pc = left.Type as PointerContainer;
5955 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5956 Error_VoidPointerOperation (ec);
5963 public override void Emit (EmitContext ec)
5965 TypeSpec op_type = left.Type;
5967 // It must be either array or fixed buffer
5969 if (TypeManager.HasElementType (op_type)) {
5970 element = TypeManager.GetElementType (op_type);
5972 FieldExpr fe = left as FieldExpr;
5974 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5979 int size = BuiltinTypeSpec.GetSize(element);
5980 TypeSpec rtype = right.Type;
5982 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5984 // handle (pointer - pointer)
5988 ec.Emit (OpCodes.Sub);
5992 ec.Emit (OpCodes.Sizeof, element);
5995 ec.Emit (OpCodes.Div);
5997 ec.Emit (OpCodes.Conv_I8);
6000 // handle + and - on (pointer op int)
6002 Constant left_const = left as Constant;
6003 if (left_const != null) {
6005 // Optimize ((T*)null) pointer operations
6007 if (left_const.IsDefaultValue) {
6008 left = EmptyExpression.Null;
6016 var right_const = right as Constant;
6017 if (right_const != null) {
6019 // Optimize 0-based arithmetic
6021 if (right_const.IsDefaultValue)
6025 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6027 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6029 // TODO: Should be the checks resolve context sensitive?
6030 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6031 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6037 switch (rtype.BuiltinType) {
6038 case BuiltinTypeSpec.Type.SByte:
6039 case BuiltinTypeSpec.Type.Byte:
6040 case BuiltinTypeSpec.Type.Short:
6041 case BuiltinTypeSpec.Type.UShort:
6042 ec.Emit (OpCodes.Conv_I);
6044 case BuiltinTypeSpec.Type.UInt:
6045 ec.Emit (OpCodes.Conv_U);
6049 if (right_const == null && size != 1){
6051 ec.Emit (OpCodes.Sizeof, element);
6054 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6055 ec.Emit (OpCodes.Conv_I8);
6057 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6060 if (left_const == null) {
6061 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6062 ec.Emit (OpCodes.Conv_I);
6063 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6064 ec.Emit (OpCodes.Conv_U);
6066 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6073 // A boolean-expression is an expression that yields a result
6076 public class BooleanExpression : ShimExpression
6078 public BooleanExpression (Expression expr)
6081 this.loc = expr.Location;
6084 public override Expression CreateExpressionTree (ResolveContext ec)
6086 // TODO: We should emit IsTrue (v4) instead of direct user operator
6087 // call but that would break csc compatibility
6088 return base.CreateExpressionTree (ec);
6091 protected override Expression DoResolve (ResolveContext ec)
6093 // A boolean-expression is required to be of a type
6094 // that can be implicitly converted to bool or of
6095 // a type that implements operator true
6097 expr = expr.Resolve (ec);
6101 Assign ass = expr as Assign;
6102 if (ass != null && ass.Source is Constant) {
6103 ec.Report.Warning (665, 3, loc,
6104 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6107 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6110 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6111 Arguments args = new Arguments (1);
6112 args.Add (new Argument (expr));
6113 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6116 type = ec.BuiltinTypes.Bool;
6117 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6118 if (converted != null)
6122 // If no implicit conversion to bool exists, try using `operator true'
6124 converted = GetOperatorTrue (ec, expr, loc);
6125 if (converted == null) {
6126 expr.Error_ValueCannotBeConverted (ec, type, false);
6133 public override object Accept (StructuralVisitor visitor)
6135 return visitor.Visit (this);
6139 public class BooleanExpressionFalse : Unary
6141 public BooleanExpressionFalse (Expression expr)
6142 : base (Operator.LogicalNot, expr, expr.Location)
6146 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6148 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6153 /// Implements the ternary conditional operator (?:)
6155 public class Conditional : Expression {
6156 Expression expr, true_expr, false_expr;
6158 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6161 this.true_expr = true_expr;
6162 this.false_expr = false_expr;
6168 public Expression Expr {
6174 public Expression TrueExpr {
6180 public Expression FalseExpr {
6188 public override bool ContainsEmitWithAwait ()
6190 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6193 public override Expression CreateExpressionTree (ResolveContext ec)
6195 Arguments args = new Arguments (3);
6196 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6197 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6198 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6199 return CreateExpressionFactoryCall (ec, "Condition", args);
6202 protected override Expression DoResolve (ResolveContext ec)
6204 expr = expr.Resolve (ec);
6205 true_expr = true_expr.Resolve (ec);
6206 false_expr = false_expr.Resolve (ec);
6208 if (true_expr == null || false_expr == null || expr == null)
6211 eclass = ExprClass.Value;
6212 TypeSpec true_type = true_expr.Type;
6213 TypeSpec false_type = false_expr.Type;
6217 // First, if an implicit conversion exists from true_expr
6218 // to false_expr, then the result type is of type false_expr.Type
6220 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6221 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6222 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6224 // Check if both can convert implicitly to each other's type
6228 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6229 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6231 // LAMESPEC: There seems to be hardcoded promotition to int type when
6232 // both sides are numeric constants and one side is int constant and
6233 // other side is numeric constant convertible to int.
6235 // var res = condition ? (short)1 : 1;
6237 // Type of res is int even if according to the spec the conversion is
6238 // ambiguous because 1 literal can be converted to short.
6240 if (conv_false_expr != null) {
6241 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6243 conv_false_expr = null;
6244 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6245 conv_false_expr = null;
6249 if (conv_false_expr != null) {
6250 ec.Report.Error (172, true_expr.Location,
6251 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6252 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6257 if (true_expr.Type != type)
6258 true_expr = EmptyCast.Create (true_expr, type);
6259 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6262 if (false_type != InternalType.ErrorType) {
6263 ec.Report.Error (173, true_expr.Location,
6264 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6265 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6271 Constant c = expr as Constant;
6273 bool is_false = c.IsDefaultValue;
6276 // Don't issue the warning for constant expressions
6278 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6279 // CSC: Missing warning
6280 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6283 return ReducedExpression.Create (
6284 is_false ? false_expr : true_expr, this,
6285 false_expr is Constant && true_expr is Constant).Resolve (ec);
6291 public override void Emit (EmitContext ec)
6293 Label false_target = ec.DefineLabel ();
6294 Label end_target = ec.DefineLabel ();
6296 expr.EmitBranchable (ec, false_target, false);
6297 true_expr.Emit (ec);
6300 // Verifier doesn't support interface merging. When there are two types on
6301 // the stack without common type hint and the common type is an interface.
6302 // Use temporary local to give verifier hint on what type to unify the stack
6304 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6305 var temp = ec.GetTemporaryLocal (type);
6306 ec.Emit (OpCodes.Stloc, temp);
6307 ec.Emit (OpCodes.Ldloc, temp);
6308 ec.FreeTemporaryLocal (temp, type);
6311 ec.Emit (OpCodes.Br, end_target);
6312 ec.MarkLabel (false_target);
6313 false_expr.Emit (ec);
6314 ec.MarkLabel (end_target);
6317 public override void FlowAnalysis (FlowAnalysisContext fc)
6319 expr.FlowAnalysisConditional (fc);
6320 var expr_true = fc.DefiniteAssignmentOnTrue;
6321 var expr_false = fc.DefiniteAssignmentOnFalse;
6323 fc.BranchDefiniteAssignment (expr_true);
6324 true_expr.FlowAnalysis (fc);
6325 var true_fc = fc.DefiniteAssignment;
6327 fc.BranchDefiniteAssignment (expr_false);
6328 false_expr.FlowAnalysis (fc);
6330 fc.DefiniteAssignment &= true_fc;
6333 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6335 expr.FlowAnalysisConditional (fc);
6336 var expr_true = fc.DefiniteAssignmentOnTrue;
6337 var expr_false = fc.DefiniteAssignmentOnFalse;
6339 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6340 true_expr.FlowAnalysisConditional (fc);
6341 var true_fc = fc.DefiniteAssignment;
6342 var true_da_true = fc.DefiniteAssignmentOnTrue;
6343 var true_da_false = fc.DefiniteAssignmentOnFalse;
6345 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6346 false_expr.FlowAnalysisConditional (fc);
6348 fc.DefiniteAssignment &= true_fc;
6349 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6350 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6353 protected override void CloneTo (CloneContext clonectx, Expression t)
6355 Conditional target = (Conditional) t;
6357 target.expr = expr.Clone (clonectx);
6358 target.true_expr = true_expr.Clone (clonectx);
6359 target.false_expr = false_expr.Clone (clonectx);
6363 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6365 LocalTemporary temp;
6368 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6369 public abstract void SetHasAddressTaken ();
6371 public abstract bool IsLockedByStatement { get; set; }
6373 public abstract bool IsFixed { get; }
6374 public abstract bool IsRef { get; }
6375 public abstract string Name { get; }
6378 // Variable IL data, it has to be protected to encapsulate hoisted variables
6380 protected abstract ILocalVariable Variable { get; }
6383 // Variable flow-analysis data
6385 public abstract VariableInfo VariableInfo { get; }
6388 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6390 HoistedVariable hv = GetHoistedVariable (ec);
6392 hv.AddressOf (ec, mode);
6396 Variable.EmitAddressOf (ec);
6399 public override bool ContainsEmitWithAwait ()
6404 public override Expression CreateExpressionTree (ResolveContext ec)
6406 HoistedVariable hv = GetHoistedVariable (ec);
6408 return hv.CreateExpressionTree ();
6410 Arguments arg = new Arguments (1);
6411 arg.Add (new Argument (this));
6412 return CreateExpressionFactoryCall (ec, "Constant", arg);
6415 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6417 if (IsLockedByStatement) {
6418 rc.Report.Warning (728, 2, loc,
6419 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6426 public override void Emit (EmitContext ec)
6431 public override void EmitSideEffect (EmitContext ec)
6437 // This method is used by parameters that are references, that are
6438 // being passed as references: we only want to pass the pointer (that
6439 // is already stored in the parameter, not the address of the pointer,
6440 // and not the value of the variable).
6442 public void EmitLoad (EmitContext ec)
6447 public void Emit (EmitContext ec, bool leave_copy)
6449 HoistedVariable hv = GetHoistedVariable (ec);
6451 hv.Emit (ec, leave_copy);
6459 // If we are a reference, we loaded on the stack a pointer
6460 // Now lets load the real value
6462 ec.EmitLoadFromPtr (type);
6466 ec.Emit (OpCodes.Dup);
6469 temp = new LocalTemporary (Type);
6475 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6476 bool prepare_for_load)
6478 HoistedVariable hv = GetHoistedVariable (ec);
6480 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6484 New n_source = source as New;
6485 if (n_source != null) {
6486 if (!n_source.Emit (ec, this)) {
6490 ec.EmitLoadFromPtr (type);
6502 ec.Emit (OpCodes.Dup);
6504 temp = new LocalTemporary (Type);
6510 ec.EmitStoreFromPtr (type);
6512 Variable.EmitAssign (ec);
6520 public override Expression EmitToField (EmitContext ec)
6522 HoistedVariable hv = GetHoistedVariable (ec);
6524 return hv.EmitToField (ec);
6527 return base.EmitToField (ec);
6530 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6532 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6535 public HoistedVariable GetHoistedVariable (EmitContext ec)
6537 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6540 public override string GetSignatureForError ()
6545 public bool IsHoisted {
6546 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6551 // Resolved reference to a local variable
6553 public class LocalVariableReference : VariableReference
6555 public LocalVariable local_info;
6557 public LocalVariableReference (LocalVariable li, Location l)
6559 this.local_info = li;
6563 public override VariableInfo VariableInfo {
6564 get { return local_info.VariableInfo; }
6567 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6569 return local_info.HoistedVariant;
6575 // A local variable is always fixed
6577 public override bool IsFixed {
6583 public override bool IsLockedByStatement {
6585 return local_info.IsLocked;
6588 local_info.IsLocked = value;
6592 public override bool IsRef {
6593 get { return false; }
6596 public override string Name {
6597 get { return local_info.Name; }
6602 public override void FlowAnalysis (FlowAnalysisContext fc)
6604 VariableInfo variable_info = VariableInfo;
6605 if (variable_info == null)
6608 if (fc.IsDefinitelyAssigned (variable_info))
6611 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6612 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6615 public override void SetHasAddressTaken ()
6617 local_info.SetHasAddressTaken ();
6620 void DoResolveBase (ResolveContext ec)
6622 eclass = ExprClass.Variable;
6623 type = local_info.Type;
6626 // If we are referencing a variable from the external block
6627 // flag it for capturing
6629 if (ec.MustCaptureVariable (local_info)) {
6630 if (local_info.AddressTaken) {
6631 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6632 } else if (local_info.IsFixed) {
6633 ec.Report.Error (1764, loc,
6634 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6635 GetSignatureForError ());
6638 if (ec.IsVariableCapturingRequired) {
6639 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6640 storey.CaptureLocalVariable (ec, local_info);
6645 protected override Expression DoResolve (ResolveContext ec)
6647 local_info.SetIsUsed ();
6651 if (local_info.Type == InternalType.VarOutType) {
6652 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6653 GetSignatureForError ());
6655 type = InternalType.ErrorType;
6661 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6664 // Don't be too pedantic when variable is used as out param or for some broken code
6665 // which uses property/indexer access to run some initialization
6667 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6668 local_info.SetIsUsed ();
6670 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6671 if (rhs == EmptyExpression.LValueMemberAccess) {
6672 // CS1654 already reported
6676 if (rhs == EmptyExpression.OutAccess) {
6677 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6678 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6679 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6680 } else if (rhs == EmptyExpression.UnaryAddress) {
6681 code = 459; msg = "Cannot take the address of {1} `{0}'";
6683 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6685 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6689 if (eclass == ExprClass.Unresolved)
6692 return base.DoResolveLValue (ec, rhs);
6695 public override int GetHashCode ()
6697 return local_info.GetHashCode ();
6700 public override bool Equals (object obj)
6702 LocalVariableReference lvr = obj as LocalVariableReference;
6706 return local_info == lvr.local_info;
6709 protected override ILocalVariable Variable {
6710 get { return local_info; }
6713 public override string ToString ()
6715 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6718 protected override void CloneTo (CloneContext clonectx, Expression t)
6725 /// This represents a reference to a parameter in the intermediate
6728 public class ParameterReference : VariableReference
6730 protected ParametersBlock.ParameterInfo pi;
6732 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6740 public override bool IsLockedByStatement {
6745 pi.IsLocked = value;
6749 public override bool IsRef {
6750 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6753 bool HasOutModifier {
6754 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6757 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6759 return pi.Parameter.HoistedVariant;
6763 // A ref or out parameter is classified as a moveable variable, even
6764 // if the argument given for the parameter is a fixed variable
6766 public override bool IsFixed {
6767 get { return !IsRef; }
6770 public override string Name {
6771 get { return Parameter.Name; }
6774 public Parameter Parameter {
6775 get { return pi.Parameter; }
6778 public override VariableInfo VariableInfo {
6779 get { return pi.VariableInfo; }
6782 protected override ILocalVariable Variable {
6783 get { return Parameter; }
6788 public override void AddressOf (EmitContext ec, AddressOp mode)
6791 // ParameterReferences might already be a reference
6798 base.AddressOf (ec, mode);
6801 public override void SetHasAddressTaken ()
6803 Parameter.HasAddressTaken = true;
6806 bool DoResolveBase (ResolveContext ec)
6808 if (eclass != ExprClass.Unresolved)
6811 type = pi.ParameterType;
6812 eclass = ExprClass.Variable;
6815 // If we are referencing a parameter from the external block
6816 // flag it for capturing
6818 if (ec.MustCaptureVariable (pi)) {
6819 if (Parameter.HasAddressTaken)
6820 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6823 ec.Report.Error (1628, loc,
6824 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6825 Name, ec.CurrentAnonymousMethod.ContainerType);
6828 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6829 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6830 storey.CaptureParameter (ec, pi, this);
6837 public override int GetHashCode ()
6839 return Name.GetHashCode ();
6842 public override bool Equals (object obj)
6844 ParameterReference pr = obj as ParameterReference;
6848 return Name == pr.Name;
6851 protected override void CloneTo (CloneContext clonectx, Expression target)
6857 public override Expression CreateExpressionTree (ResolveContext ec)
6859 HoistedVariable hv = GetHoistedVariable (ec);
6861 return hv.CreateExpressionTree ();
6863 return Parameter.ExpressionTreeVariableReference ();
6866 protected override Expression DoResolve (ResolveContext ec)
6868 if (!DoResolveBase (ec))
6874 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6876 if (!DoResolveBase (ec))
6879 if (Parameter.HoistedVariant != null)
6880 Parameter.HoistedVariant.IsAssigned = true;
6882 return base.DoResolveLValue (ec, right_side);
6885 public override void FlowAnalysis (FlowAnalysisContext fc)
6887 VariableInfo variable_info = VariableInfo;
6888 if (variable_info == null)
6891 if (fc.IsDefinitelyAssigned (variable_info))
6894 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6895 fc.SetVariableAssigned (variable_info);
6900 /// Invocation of methods or delegates.
6902 public class Invocation : ExpressionStatement
6904 public class Predefined : Invocation
6906 public Predefined (MethodGroupExpr expr, Arguments arguments)
6907 : base (expr, arguments)
6912 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6914 mg.BestCandidate.CheckObsoleteness (rc, loc);
6920 protected Arguments arguments;
6921 protected Expression expr;
6922 protected MethodGroupExpr mg;
6923 bool conditional_access_receiver;
6925 public Invocation (Expression expr, Arguments arguments)
6928 this.arguments = arguments;
6930 loc = expr.Location;
6935 public Arguments Arguments {
6941 public Expression Exp {
6947 public MethodGroupExpr MethodGroup {
6953 public override Location StartLocation {
6955 return expr.StartLocation;
6961 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6963 if (MethodGroup == null)
6966 var candidate = MethodGroup.BestCandidate;
6967 if (candidate == null || !(candidate.IsStatic || Exp is This))
6970 var args_count = arguments == null ? 0 : arguments.Count;
6971 if (args_count != body.Parameters.Count)
6974 var lambda_parameters = body.Block.Parameters.FixedParameters;
6975 for (int i = 0; i < args_count; ++i) {
6976 var pr = arguments[i].Expr as ParameterReference;
6980 if (lambda_parameters[i] != pr.Parameter)
6983 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6987 var emg = MethodGroup as ExtensionMethodGroupExpr;
6989 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6990 if (candidate.IsGeneric) {
6991 var targs = new TypeExpression [candidate.Arity];
6992 for (int i = 0; i < targs.Length; ++i) {
6993 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6996 mg.SetTypeArguments (null, new TypeArguments (targs));
7005 protected override void CloneTo (CloneContext clonectx, Expression t)
7007 Invocation target = (Invocation) t;
7009 if (arguments != null)
7010 target.arguments = arguments.Clone (clonectx);
7012 target.expr = expr.Clone (clonectx);
7015 public override bool ContainsEmitWithAwait ()
7017 if (arguments != null && arguments.ContainsEmitWithAwait ())
7020 return mg.ContainsEmitWithAwait ();
7023 public override Expression CreateExpressionTree (ResolveContext ec)
7025 Expression instance = mg.IsInstance ?
7026 mg.InstanceExpression.CreateExpressionTree (ec) :
7027 new NullLiteral (loc);
7029 var args = Arguments.CreateForExpressionTree (ec, arguments,
7031 mg.CreateExpressionTree (ec));
7033 return CreateExpressionFactoryCall (ec, "Call", args);
7036 protected override Expression DoResolve (ResolveContext rc)
7038 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
7039 if (expr.HasConditionalAccess ()) {
7040 conditional_access_receiver = true;
7041 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
7042 return DoResolveInvocation (rc);
7047 return DoResolveInvocation (rc);
7050 Expression DoResolveInvocation (ResolveContext ec)
7052 Expression member_expr;
7053 var atn = expr as ATypeNameExpression;
7055 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7056 if (member_expr != null) {
7057 var name_of = member_expr as NameOf;
7058 if (name_of != null) {
7059 return name_of.ResolveOverload (ec, arguments);
7062 member_expr = member_expr.Resolve (ec);
7065 member_expr = expr.Resolve (ec);
7068 if (member_expr == null)
7072 // Next, evaluate all the expressions in the argument list
7074 bool dynamic_arg = false;
7075 if (arguments != null)
7076 arguments.Resolve (ec, out dynamic_arg);
7078 TypeSpec expr_type = member_expr.Type;
7079 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7080 return DoResolveDynamic (ec, member_expr);
7082 mg = member_expr as MethodGroupExpr;
7083 Expression invoke = null;
7086 if (expr_type != null && expr_type.IsDelegate) {
7087 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7088 invoke = invoke.Resolve (ec);
7089 if (invoke == null || !dynamic_arg)
7092 if (member_expr is RuntimeValueExpression) {
7093 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7094 member_expr.Type.GetSignatureForError ());
7098 MemberExpr me = member_expr as MemberExpr;
7100 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7104 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7105 member_expr.GetSignatureForError ());
7110 if (invoke == null) {
7111 mg = DoResolveOverload (ec);
7117 return DoResolveDynamic (ec, member_expr);
7119 var method = mg.BestCandidate;
7120 type = mg.BestCandidateReturnType;
7121 if (conditional_access_receiver)
7122 type = LiftMemberType (ec, type);
7124 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7126 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7128 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7132 IsSpecialMethodInvocation (ec, method, loc);
7134 eclass = ExprClass.Value;
7138 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7141 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7143 args = dmb.Arguments;
7144 if (arguments != null)
7145 args.AddRange (arguments);
7146 } else if (mg == null) {
7147 if (arguments == null)
7148 args = new Arguments (1);
7152 args.Insert (0, new Argument (memberExpr));
7156 ec.Report.Error (1971, loc,
7157 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7162 if (arguments == null)
7163 args = new Arguments (1);
7167 MemberAccess ma = expr as MemberAccess;
7169 var inst = mg.InstanceExpression;
7170 var left_type = inst as TypeExpr;
7171 if (left_type != null) {
7172 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7173 } else if (inst != null) {
7175 // Any value type has to be pass as by-ref to get back the same
7176 // instance on which the member was called
7178 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7179 Argument.AType.Ref : Argument.AType.None;
7180 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7182 } else { // is SimpleName
7184 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7186 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7191 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7194 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7196 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7199 public override void FlowAnalysis (FlowAnalysisContext fc)
7201 if (mg.IsConditionallyExcluded)
7204 mg.FlowAnalysis (fc);
7206 if (arguments != null)
7207 arguments.FlowAnalysis (fc);
7209 if (conditional_access_receiver)
7210 fc.ConditionalAccessEnd ();
7213 public override string GetSignatureForError ()
7215 return mg.GetSignatureForError ();
7218 public override bool HasConditionalAccess ()
7220 return expr.HasConditionalAccess ();
7224 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7225 // or the type dynamic, then the member is invocable
7227 public static bool IsMemberInvocable (MemberSpec member)
7229 switch (member.Kind) {
7230 case MemberKind.Event:
7232 case MemberKind.Field:
7233 case MemberKind.Property:
7234 var m = member as IInterfaceMemberSpec;
7235 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7241 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7243 if (!method.IsReservedMethod)
7246 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7249 ec.Report.SymbolRelatedToPreviousError (method);
7250 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7251 method.GetSignatureForError ());
7256 public override void Emit (EmitContext ec)
7258 if (mg.IsConditionallyExcluded)
7261 if (conditional_access_receiver)
7262 mg.EmitCall (ec, arguments, type, false);
7264 mg.EmitCall (ec, arguments, false);
7267 public override void EmitStatement (EmitContext ec)
7269 if (mg.IsConditionallyExcluded)
7272 if (conditional_access_receiver)
7273 mg.EmitCall (ec, arguments, type, true);
7275 mg.EmitCall (ec, arguments, true);
7278 public override SLE.Expression MakeExpression (BuilderContext ctx)
7280 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7283 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7286 throw new NotSupportedException ();
7288 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7289 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7293 public override object Accept (StructuralVisitor visitor)
7295 return visitor.Visit (this);
7300 // Implements simple new expression
7302 public class New : ExpressionStatement, IMemoryLocation
7304 protected Arguments arguments;
7307 // During bootstrap, it contains the RequestedType,
7308 // but if `type' is not null, it *might* contain a NewDelegate
7309 // (because of field multi-initialization)
7311 protected Expression RequestedType;
7313 protected MethodSpec method;
7315 public New (Expression requested_type, Arguments arguments, Location l)
7317 RequestedType = requested_type;
7318 this.arguments = arguments;
7323 public Arguments Arguments {
7330 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7332 public bool IsGeneratedStructConstructor {
7334 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7338 public Expression TypeExpression {
7340 return RequestedType;
7347 /// Converts complex core type syntax like 'new int ()' to simple constant
7349 public static Constant Constantify (TypeSpec t, Location loc)
7351 switch (t.BuiltinType) {
7352 case BuiltinTypeSpec.Type.Int:
7353 return new IntConstant (t, 0, loc);
7354 case BuiltinTypeSpec.Type.UInt:
7355 return new UIntConstant (t, 0, loc);
7356 case BuiltinTypeSpec.Type.Long:
7357 return new LongConstant (t, 0, loc);
7358 case BuiltinTypeSpec.Type.ULong:
7359 return new ULongConstant (t, 0, loc);
7360 case BuiltinTypeSpec.Type.Float:
7361 return new FloatConstant (t, 0, loc);
7362 case BuiltinTypeSpec.Type.Double:
7363 return new DoubleConstant (t, 0, loc);
7364 case BuiltinTypeSpec.Type.Short:
7365 return new ShortConstant (t, 0, loc);
7366 case BuiltinTypeSpec.Type.UShort:
7367 return new UShortConstant (t, 0, loc);
7368 case BuiltinTypeSpec.Type.SByte:
7369 return new SByteConstant (t, 0, loc);
7370 case BuiltinTypeSpec.Type.Byte:
7371 return new ByteConstant (t, 0, loc);
7372 case BuiltinTypeSpec.Type.Char:
7373 return new CharConstant (t, '\0', loc);
7374 case BuiltinTypeSpec.Type.Bool:
7375 return new BoolConstant (t, false, loc);
7376 case BuiltinTypeSpec.Type.Decimal:
7377 return new DecimalConstant (t, 0, loc);
7381 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7383 if (t.IsNullableType)
7384 return Nullable.LiftedNull.Create (t, loc);
7389 public override bool ContainsEmitWithAwait ()
7391 return arguments != null && arguments.ContainsEmitWithAwait ();
7395 // Checks whether the type is an interface that has the
7396 // [ComImport, CoClass] attributes and must be treated
7399 public Expression CheckComImport (ResolveContext ec)
7401 if (!type.IsInterface)
7405 // Turn the call into:
7406 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7408 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7409 if (real_class == null)
7412 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7413 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7414 return cast.Resolve (ec);
7417 public override Expression CreateExpressionTree (ResolveContext ec)
7420 if (method == null) {
7421 args = new Arguments (1);
7422 args.Add (new Argument (new TypeOf (type, loc)));
7424 args = Arguments.CreateForExpressionTree (ec,
7425 arguments, new TypeOfMethod (method, loc));
7428 return CreateExpressionFactoryCall (ec, "New", args);
7431 protected override Expression DoResolve (ResolveContext ec)
7433 type = RequestedType.ResolveAsType (ec);
7437 eclass = ExprClass.Value;
7439 if (type.IsPointer) {
7440 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7441 type.GetSignatureForError ());
7445 if (arguments == null) {
7446 Constant c = Constantify (type, RequestedType.Location);
7448 return ReducedExpression.Create (c, this);
7451 if (type.IsDelegate) {
7452 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7455 var tparam = type as TypeParameterSpec;
7456 if (tparam != null) {
7458 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7459 // where type parameter constraint is inflated to struct
7461 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7462 ec.Report.Error (304, loc,
7463 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7464 type.GetSignatureForError ());
7467 if ((arguments != null) && (arguments.Count != 0)) {
7468 ec.Report.Error (417, loc,
7469 "`{0}': cannot provide arguments when creating an instance of a variable type",
7470 type.GetSignatureForError ());
7476 if (type.IsStatic) {
7477 ec.Report.SymbolRelatedToPreviousError (type);
7478 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7482 if (type.IsInterface || type.IsAbstract){
7483 if (!TypeManager.IsGenericType (type)) {
7484 RequestedType = CheckComImport (ec);
7485 if (RequestedType != null)
7486 return RequestedType;
7489 ec.Report.SymbolRelatedToPreviousError (type);
7490 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7495 if (arguments != null) {
7496 arguments.Resolve (ec, out dynamic);
7501 method = ConstructorLookup (ec, type, ref arguments, loc);
7504 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7505 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7511 void DoEmitTypeParameter (EmitContext ec)
7513 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7517 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7518 ec.Emit (OpCodes.Call, ctor_factory);
7522 // This Emit can be invoked in two contexts:
7523 // * As a mechanism that will leave a value on the stack (new object)
7524 // * As one that wont (init struct)
7526 // If we are dealing with a ValueType, we have a few
7527 // situations to deal with:
7529 // * The target is a ValueType, and we have been provided
7530 // the instance (this is easy, we are being assigned).
7532 // * The target of New is being passed as an argument,
7533 // to a boxing operation or a function that takes a
7536 // In this case, we need to create a temporary variable
7537 // that is the argument of New.
7539 // Returns whether a value is left on the stack
7541 // *** Implementation note ***
7543 // To benefit from this optimization, each assignable expression
7544 // has to manually cast to New and call this Emit.
7546 // TODO: It's worth to implement it for arrays and fields
7548 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7550 bool is_value_type = type.IsStructOrEnum;
7551 VariableReference vr = target as VariableReference;
7553 if (target != null && is_value_type && (vr != null || method == null)) {
7554 target.AddressOf (ec, AddressOp.Store);
7555 } else if (vr != null && vr.IsRef) {
7559 if (arguments != null) {
7560 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7561 arguments = arguments.Emit (ec, false, true);
7563 arguments.Emit (ec);
7566 if (is_value_type) {
7567 if (method == null) {
7568 ec.Emit (OpCodes.Initobj, type);
7573 ec.MarkCallEntry (loc);
7574 ec.Emit (OpCodes.Call, method);
7579 if (type is TypeParameterSpec) {
7580 DoEmitTypeParameter (ec);
7584 ec.MarkCallEntry (loc);
7585 ec.Emit (OpCodes.Newobj, method);
7589 public override void Emit (EmitContext ec)
7591 LocalTemporary v = null;
7592 if (method == null && type.IsStructOrEnum) {
7593 // TODO: Use temporary variable from pool
7594 v = new LocalTemporary (type);
7601 public override void EmitStatement (EmitContext ec)
7603 LocalTemporary v = null;
7604 if (method == null && TypeSpec.IsValueType (type)) {
7605 // TODO: Use temporary variable from pool
7606 v = new LocalTemporary (type);
7610 ec.Emit (OpCodes.Pop);
7613 public override void FlowAnalysis (FlowAnalysisContext fc)
7615 if (arguments != null)
7616 arguments.FlowAnalysis (fc);
7619 public void AddressOf (EmitContext ec, AddressOp mode)
7621 EmitAddressOf (ec, mode);
7624 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7626 LocalTemporary value_target = new LocalTemporary (type);
7628 if (type is TypeParameterSpec) {
7629 DoEmitTypeParameter (ec);
7630 value_target.Store (ec);
7631 value_target.AddressOf (ec, mode);
7632 return value_target;
7635 value_target.AddressOf (ec, AddressOp.Store);
7637 if (method == null) {
7638 ec.Emit (OpCodes.Initobj, type);
7640 if (arguments != null)
7641 arguments.Emit (ec);
7643 ec.Emit (OpCodes.Call, method);
7646 value_target.AddressOf (ec, mode);
7647 return value_target;
7650 protected override void CloneTo (CloneContext clonectx, Expression t)
7652 New target = (New) t;
7654 target.RequestedType = RequestedType.Clone (clonectx);
7655 if (arguments != null){
7656 target.arguments = arguments.Clone (clonectx);
7660 public override SLE.Expression MakeExpression (BuilderContext ctx)
7663 return base.MakeExpression (ctx);
7665 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7669 public override object Accept (StructuralVisitor visitor)
7671 return visitor.Visit (this);
7676 // Array initializer expression, the expression is allowed in
7677 // variable or field initialization only which makes it tricky as
7678 // the type has to be infered based on the context either from field
7679 // type or variable type (think of multiple declarators)
7681 public class ArrayInitializer : Expression
7683 List<Expression> elements;
7684 BlockVariable variable;
7686 public ArrayInitializer (List<Expression> init, Location loc)
7692 public ArrayInitializer (int count, Location loc)
7693 : this (new List<Expression> (count), loc)
7697 public ArrayInitializer (Location loc)
7705 get { return elements.Count; }
7708 public List<Expression> Elements {
7714 public Expression this [int index] {
7716 return elements [index];
7720 public BlockVariable VariableDeclaration {
7731 public void Add (Expression expr)
7733 elements.Add (expr);
7736 public override bool ContainsEmitWithAwait ()
7738 throw new NotSupportedException ();
7741 public override Expression CreateExpressionTree (ResolveContext ec)
7743 throw new NotSupportedException ("ET");
7746 protected override void CloneTo (CloneContext clonectx, Expression t)
7748 var target = (ArrayInitializer) t;
7750 target.elements = new List<Expression> (elements.Count);
7751 foreach (var element in elements)
7752 target.elements.Add (element.Clone (clonectx));
7755 protected override Expression DoResolve (ResolveContext rc)
7757 var current_field = rc.CurrentMemberDefinition as FieldBase;
7758 TypeExpression type;
7759 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7760 type = new TypeExpression (current_field.MemberType, current_field.Location);
7761 } else if (variable != null) {
7762 if (variable.TypeExpression is VarExpr) {
7763 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7764 return EmptyExpression.Null;
7767 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7769 throw new NotImplementedException ("Unexpected array initializer context");
7772 return new ArrayCreation (type, this).Resolve (rc);
7775 public override void Emit (EmitContext ec)
7777 throw new InternalErrorException ("Missing Resolve call");
7780 public override void FlowAnalysis (FlowAnalysisContext fc)
7782 throw new InternalErrorException ("Missing Resolve call");
7785 public override object Accept (StructuralVisitor visitor)
7787 return visitor.Visit (this);
7792 /// 14.5.10.2: Represents an array creation expression.
7796 /// There are two possible scenarios here: one is an array creation
7797 /// expression that specifies the dimensions and optionally the
7798 /// initialization data and the other which does not need dimensions
7799 /// specified but where initialization data is mandatory.
7801 public class ArrayCreation : Expression
7803 FullNamedExpression requested_base_type;
7804 ArrayInitializer initializers;
7807 // The list of Argument types.
7808 // This is used to construct the `newarray' or constructor signature
7810 protected List<Expression> arguments;
7812 protected TypeSpec array_element_type;
7814 protected int dimensions;
7815 protected readonly ComposedTypeSpecifier rank;
7816 Expression first_emit;
7817 LocalTemporary first_emit_temp;
7819 protected List<Expression> array_data;
7821 Dictionary<int, int> bounds;
7824 // The number of constants in array initializers
7825 int const_initializers_count;
7826 bool only_constant_initializers;
7828 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7829 : this (requested_base_type, rank, initializers, l)
7831 arguments = new List<Expression> (exprs);
7832 num_arguments = arguments.Count;
7836 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7838 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7840 this.requested_base_type = requested_base_type;
7842 this.initializers = initializers;
7846 num_arguments = rank.Dimension;
7850 // For compiler generated single dimensional arrays only
7852 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7853 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7858 // For expressions like int[] foo = { 1, 2, 3 };
7860 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7861 : this (requested_base_type, null, initializers, initializers.Location)
7865 public ComposedTypeSpecifier Rank {
7871 public FullNamedExpression TypeExpression {
7873 return this.requested_base_type;
7877 public ArrayInitializer Initializers {
7879 return this.initializers;
7883 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7885 if (initializers != null && bounds == null) {
7887 // We use this to store all the data values in the order in which we
7888 // will need to store them in the byte blob later
7890 array_data = new List<Expression> (probe.Count);
7891 bounds = new Dictionary<int, int> ();
7894 if (specified_dims) {
7895 Expression a = arguments [idx];
7900 a = ConvertExpressionToArrayIndex (ec, a);
7906 if (initializers != null) {
7907 Constant c = a as Constant;
7908 if (c == null && a is ArrayIndexCast)
7909 c = ((ArrayIndexCast) a).Child as Constant;
7912 ec.Report.Error (150, a.Location, "A constant value is expected");
7918 value = System.Convert.ToInt32 (c.GetValue ());
7920 ec.Report.Error (150, a.Location, "A constant value is expected");
7924 // TODO: probe.Count does not fit ulong in
7925 if (value != probe.Count) {
7926 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7930 bounds[idx] = value;
7934 if (initializers == null)
7937 for (int i = 0; i < probe.Count; ++i) {
7939 if (o is ArrayInitializer) {
7940 var sub_probe = o as ArrayInitializer;
7941 if (idx + 1 >= dimensions){
7942 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7946 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7947 if (!bounds.ContainsKey(idx + 1))
7948 bounds[idx + 1] = sub_probe.Count;
7950 if (bounds[idx + 1] != sub_probe.Count) {
7951 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7955 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7958 } else if (child_bounds > 1) {
7959 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7961 Expression element = ResolveArrayElement (ec, o);
7962 if (element == null)
7965 // Initializers with the default values can be ignored
7966 Constant c = element as Constant;
7968 if (!c.IsDefaultInitializer (array_element_type)) {
7969 ++const_initializers_count;
7972 only_constant_initializers = false;
7975 array_data.Add (element);
7982 public override bool ContainsEmitWithAwait ()
7984 foreach (var arg in arguments) {
7985 if (arg.ContainsEmitWithAwait ())
7989 return InitializersContainAwait ();
7992 public override Expression CreateExpressionTree (ResolveContext ec)
7996 if (array_data == null) {
7997 args = new Arguments (arguments.Count + 1);
7998 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7999 foreach (Expression a in arguments)
8000 args.Add (new Argument (a.CreateExpressionTree (ec)));
8002 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8005 if (dimensions > 1) {
8006 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8010 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8011 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8012 if (array_data != null) {
8013 for (int i = 0; i < array_data.Count; ++i) {
8014 Expression e = array_data [i];
8015 args.Add (new Argument (e.CreateExpressionTree (ec)));
8019 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8022 void UpdateIndices (ResolveContext rc)
8025 for (var probe = initializers; probe != null;) {
8026 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8028 bounds[i++] = probe.Count;
8030 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8031 probe = (ArrayInitializer) probe[0];
8032 } else if (dimensions > i) {
8040 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8042 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8045 public override void FlowAnalysis (FlowAnalysisContext fc)
8047 foreach (var arg in arguments)
8048 arg.FlowAnalysis (fc);
8050 if (array_data != null) {
8051 foreach (var ad in array_data)
8052 ad.FlowAnalysis (fc);
8056 bool InitializersContainAwait ()
8058 if (array_data == null)
8061 foreach (var expr in array_data) {
8062 if (expr.ContainsEmitWithAwait ())
8069 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8071 element = element.Resolve (ec);
8072 if (element == null)
8075 if (element is CompoundAssign.TargetExpression) {
8076 if (first_emit != null)
8077 throw new InternalErrorException ("Can only handle one mutator at a time");
8078 first_emit = element;
8079 element = first_emit_temp = new LocalTemporary (element.Type);
8082 return Convert.ImplicitConversionRequired (
8083 ec, element, array_element_type, loc);
8086 protected bool ResolveInitializers (ResolveContext ec)
8089 only_constant_initializers = true;
8092 if (arguments != null) {
8094 for (int i = 0; i < arguments.Count; ++i) {
8095 res &= CheckIndices (ec, initializers, i, true, dimensions);
8096 if (initializers != null)
8103 arguments = new List<Expression> ();
8105 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8114 // Resolved the type of the array
8116 bool ResolveArrayType (ResolveContext ec)
8121 FullNamedExpression array_type_expr;
8122 if (num_arguments > 0) {
8123 array_type_expr = new ComposedCast (requested_base_type, rank);
8125 array_type_expr = requested_base_type;
8128 type = array_type_expr.ResolveAsType (ec);
8129 if (array_type_expr == null)
8132 var ac = type as ArrayContainer;
8134 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8138 array_element_type = ac.Element;
8139 dimensions = ac.Rank;
8144 protected override Expression DoResolve (ResolveContext ec)
8149 if (!ResolveArrayType (ec))
8153 // validate the initializers and fill in any missing bits
8155 if (!ResolveInitializers (ec))
8158 eclass = ExprClass.Value;
8162 byte [] MakeByteBlob ()
8167 int count = array_data.Count;
8169 TypeSpec element_type = array_element_type;
8170 if (element_type.IsEnum)
8171 element_type = EnumSpec.GetUnderlyingType (element_type);
8173 factor = BuiltinTypeSpec.GetSize (element_type);
8175 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8177 data = new byte [(count * factor + 3) & ~3];
8180 for (int i = 0; i < count; ++i) {
8181 var c = array_data[i] as Constant;
8187 object v = c.GetValue ();
8189 switch (element_type.BuiltinType) {
8190 case BuiltinTypeSpec.Type.Long:
8191 long lval = (long) v;
8193 for (int j = 0; j < factor; ++j) {
8194 data[idx + j] = (byte) (lval & 0xFF);
8198 case BuiltinTypeSpec.Type.ULong:
8199 ulong ulval = (ulong) v;
8201 for (int j = 0; j < factor; ++j) {
8202 data[idx + j] = (byte) (ulval & 0xFF);
8203 ulval = (ulval >> 8);
8206 case BuiltinTypeSpec.Type.Float:
8207 var fval = SingleConverter.SingleToInt32Bits((float) v);
8209 data[idx] = (byte) (fval & 0xff);
8210 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8211 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8212 data[idx + 3] = (byte) (fval >> 24);
8214 case BuiltinTypeSpec.Type.Double:
8215 element = BitConverter.GetBytes ((double) v);
8217 for (int j = 0; j < factor; ++j)
8218 data[idx + j] = element[j];
8220 // FIXME: Handle the ARM float format.
8221 if (!BitConverter.IsLittleEndian)
8222 System.Array.Reverse (data, idx, 8);
8224 case BuiltinTypeSpec.Type.Char:
8225 int chval = (int) ((char) v);
8227 data[idx] = (byte) (chval & 0xff);
8228 data[idx + 1] = (byte) (chval >> 8);
8230 case BuiltinTypeSpec.Type.Short:
8231 int sval = (int) ((short) v);
8233 data[idx] = (byte) (sval & 0xff);
8234 data[idx + 1] = (byte) (sval >> 8);
8236 case BuiltinTypeSpec.Type.UShort:
8237 int usval = (int) ((ushort) v);
8239 data[idx] = (byte) (usval & 0xff);
8240 data[idx + 1] = (byte) (usval >> 8);
8242 case BuiltinTypeSpec.Type.Int:
8245 data[idx] = (byte) (val & 0xff);
8246 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8247 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8248 data[idx + 3] = (byte) (val >> 24);
8250 case BuiltinTypeSpec.Type.UInt:
8251 uint uval = (uint) v;
8253 data[idx] = (byte) (uval & 0xff);
8254 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8255 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8256 data[idx + 3] = (byte) (uval >> 24);
8258 case BuiltinTypeSpec.Type.SByte:
8259 data[idx] = (byte) (sbyte) v;
8261 case BuiltinTypeSpec.Type.Byte:
8262 data[idx] = (byte) v;
8264 case BuiltinTypeSpec.Type.Bool:
8265 data[idx] = (byte) ((bool) v ? 1 : 0);
8267 case BuiltinTypeSpec.Type.Decimal:
8268 int[] bits = Decimal.GetBits ((decimal) v);
8271 // FIXME: For some reason, this doesn't work on the MS runtime.
8272 int[] nbits = new int[4];
8278 for (int j = 0; j < 4; j++) {
8279 data[p++] = (byte) (nbits[j] & 0xff);
8280 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8281 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8282 data[p++] = (byte) (nbits[j] >> 24);
8286 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8295 public override SLE.Expression MakeExpression (BuilderContext ctx)
8298 return base.MakeExpression (ctx);
8300 var initializers = new SLE.Expression [array_data.Count];
8301 for (var i = 0; i < initializers.Length; i++) {
8302 if (array_data [i] == null)
8303 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8305 initializers [i] = array_data [i].MakeExpression (ctx);
8308 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8313 // Emits the initializers for the array
8315 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8317 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8322 // First, the static data
8324 byte [] data = MakeByteBlob ();
8325 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8327 if (stackArray == null) {
8328 ec.Emit (OpCodes.Dup);
8330 stackArray.Emit (ec);
8333 ec.Emit (OpCodes.Ldtoken, fb);
8334 ec.Emit (OpCodes.Call, m);
8339 // Emits pieces of the array that can not be computed at compile
8340 // time (variables and string locations).
8342 // This always expect the top value on the stack to be the array
8344 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8346 int dims = bounds.Count;
8347 var current_pos = new int [dims];
8349 for (int i = 0; i < array_data.Count; i++){
8351 Expression e = array_data [i];
8352 var c = e as Constant;
8354 // Constant can be initialized via StaticInitializer
8355 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8359 if (stackArray != null) {
8360 if (e.ContainsEmitWithAwait ()) {
8361 e = e.EmitToField (ec);
8364 stackArray.EmitLoad (ec);
8366 ec.Emit (OpCodes.Dup);
8369 for (int idx = 0; idx < dims; idx++)
8370 ec.EmitInt (current_pos [idx]);
8373 // If we are dealing with a struct, get the
8374 // address of it, so we can store it.
8376 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8377 ec.Emit (OpCodes.Ldelema, etype);
8381 ec.EmitArrayStore ((ArrayContainer) type);
8387 for (int j = dims - 1; j >= 0; j--){
8389 if (current_pos [j] < bounds [j])
8391 current_pos [j] = 0;
8395 if (stackArray != null)
8396 stackArray.PrepareCleanup (ec);
8399 public override void Emit (EmitContext ec)
8401 var await_field = EmitToFieldSource (ec);
8402 if (await_field != null)
8403 await_field.Emit (ec);
8406 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8408 if (first_emit != null) {
8409 first_emit.Emit (ec);
8410 first_emit_temp.Store (ec);
8413 StackFieldExpr await_stack_field;
8414 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8415 await_stack_field = ec.GetTemporaryField (type);
8418 await_stack_field = null;
8421 EmitExpressionsList (ec, arguments);
8423 ec.EmitArrayNew ((ArrayContainer) type);
8425 if (initializers == null)
8426 return await_stack_field;
8428 if (await_stack_field != null)
8429 await_stack_field.EmitAssignFromStack (ec);
8433 // Emit static initializer for arrays which contain more than 2 items and
8434 // the static initializer will initialize at least 25% of array values or there
8435 // is more than 10 items to be initialized
8437 // NOTE: const_initializers_count does not contain default constant values.
8439 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8440 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8441 EmitStaticInitializers (ec, await_stack_field);
8443 if (!only_constant_initializers)
8444 EmitDynamicInitializers (ec, false, await_stack_field);
8448 EmitDynamicInitializers (ec, true, await_stack_field);
8451 if (first_emit_temp != null)
8452 first_emit_temp.Release (ec);
8454 return await_stack_field;
8457 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8459 // no multi dimensional or jagged arrays
8460 if (arguments.Count != 1 || array_element_type.IsArray) {
8461 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8465 // No array covariance, except for array -> object
8466 if (type != targetType) {
8467 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8468 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8472 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8473 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8478 // Single dimensional array of 0 size
8479 if (array_data == null) {
8480 IntConstant ic = arguments[0] as IntConstant;
8481 if (ic == null || !ic.IsDefaultValue) {
8482 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8490 enc.Encode (array_data.Count);
8491 foreach (var element in array_data) {
8492 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8496 protected override void CloneTo (CloneContext clonectx, Expression t)
8498 ArrayCreation target = (ArrayCreation) t;
8500 if (requested_base_type != null)
8501 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8503 if (arguments != null){
8504 target.arguments = new List<Expression> (arguments.Count);
8505 foreach (Expression e in arguments)
8506 target.arguments.Add (e.Clone (clonectx));
8509 if (initializers != null)
8510 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8513 public override object Accept (StructuralVisitor visitor)
8515 return visitor.Visit (this);
8520 // Represents an implicitly typed array epxression
8522 class ImplicitlyTypedArrayCreation : ArrayCreation
8524 TypeInferenceContext best_type_inference;
8526 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8527 : base (null, rank, initializers, loc)
8531 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8532 : base (null, initializers, loc)
8536 protected override Expression DoResolve (ResolveContext ec)
8541 dimensions = rank.Dimension;
8543 best_type_inference = new TypeInferenceContext ();
8545 if (!ResolveInitializers (ec))
8548 best_type_inference.FixAllTypes (ec);
8549 array_element_type = best_type_inference.InferredTypeArguments[0];
8550 best_type_inference = null;
8552 if (array_element_type == null ||
8553 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8554 arguments.Count != rank.Dimension) {
8555 ec.Report.Error (826, loc,
8556 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8561 // At this point we found common base type for all initializer elements
8562 // but we have to be sure that all static initializer elements are of
8565 UnifyInitializerElement (ec);
8567 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8568 eclass = ExprClass.Value;
8573 // Converts static initializer only
8575 void UnifyInitializerElement (ResolveContext ec)
8577 for (int i = 0; i < array_data.Count; ++i) {
8578 Expression e = array_data[i];
8580 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8584 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8586 element = element.Resolve (ec);
8587 if (element != null)
8588 best_type_inference.AddCommonTypeBound (element.Type);
8594 sealed class CompilerGeneratedThis : This
8596 public CompilerGeneratedThis (TypeSpec type, Location loc)
8602 protected override Expression DoResolve (ResolveContext rc)
8604 eclass = ExprClass.Variable;
8606 var block = rc.CurrentBlock;
8607 if (block != null) {
8608 var top = block.ParametersBlock.TopBlock;
8609 if (top.ThisVariable != null)
8610 variable_info = top.ThisVariable.VariableInfo;
8617 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8619 return DoResolve (rc);
8622 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8629 /// Represents the `this' construct
8632 public class This : VariableReference
8634 sealed class ThisVariable : ILocalVariable
8636 public static readonly ILocalVariable Instance = new ThisVariable ();
8638 public void Emit (EmitContext ec)
8643 public void EmitAssign (EmitContext ec)
8645 throw new InvalidOperationException ();
8648 public void EmitAddressOf (EmitContext ec)
8654 protected VariableInfo variable_info;
8656 public This (Location loc)
8663 public override string Name {
8664 get { return "this"; }
8667 public override bool IsLockedByStatement {
8675 public override bool IsRef {
8676 get { return type.IsStruct; }
8679 public override bool IsSideEffectFree {
8685 protected override ILocalVariable Variable {
8686 get { return ThisVariable.Instance; }
8689 public override VariableInfo VariableInfo {
8690 get { return variable_info; }
8693 public override bool IsFixed {
8694 get { return false; }
8699 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8702 // It's null for all cases when we don't need to check `this'
8703 // definitive assignment
8705 if (variable_info == null)
8708 if (fc.IsDefinitelyAssigned (variable_info))
8711 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8714 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8716 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8717 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8718 } else if (ec.CurrentAnonymousMethod != null) {
8719 ec.Report.Error (1673, loc,
8720 "Anonymous methods inside structs cannot access instance members of `this'. " +
8721 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8723 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8727 public override void FlowAnalysis (FlowAnalysisContext fc)
8729 CheckStructThisDefiniteAssignment (fc);
8732 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8737 AnonymousMethodStorey storey = ae.Storey;
8738 return storey != null ? storey.HoistedThis : null;
8741 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8743 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8746 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8749 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8755 public virtual void ResolveBase (ResolveContext ec)
8757 eclass = ExprClass.Variable;
8758 type = ec.CurrentType;
8760 if (!IsThisAvailable (ec, false)) {
8761 Error_ThisNotAvailable (ec);
8765 var block = ec.CurrentBlock;
8766 if (block != null) {
8767 var top = block.ParametersBlock.TopBlock;
8768 if (top.ThisVariable != null)
8769 variable_info = top.ThisVariable.VariableInfo;
8771 AnonymousExpression am = ec.CurrentAnonymousMethod;
8772 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8774 // Hoisted this is almost like hoisted variable but not exactly. When
8775 // there is no variable hoisted we can simply emit an instance method
8776 // without lifting this into a storey. Unfotunatelly this complicates
8777 // things in other cases because we don't know where this will be hoisted
8778 // until top-level block is fully resolved
8780 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8781 am.SetHasThisAccess ();
8786 protected override Expression DoResolve (ResolveContext ec)
8792 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8794 if (eclass == ExprClass.Unresolved)
8798 if (right_side == EmptyExpression.UnaryAddress)
8799 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8800 else if (right_side == EmptyExpression.OutAccess)
8801 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8803 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8809 public override int GetHashCode()
8811 throw new NotImplementedException ();
8814 public override bool Equals (object obj)
8816 This t = obj as This;
8823 protected override void CloneTo (CloneContext clonectx, Expression t)
8828 public override void SetHasAddressTaken ()
8833 public override object Accept (StructuralVisitor visitor)
8835 return visitor.Visit (this);
8840 /// Represents the `__arglist' construct
8842 public class ArglistAccess : Expression
8844 public ArglistAccess (Location loc)
8849 protected override void CloneTo (CloneContext clonectx, Expression target)
8854 public override bool ContainsEmitWithAwait ()
8859 public override Expression CreateExpressionTree (ResolveContext ec)
8861 throw new NotSupportedException ("ET");
8864 protected override Expression DoResolve (ResolveContext ec)
8866 eclass = ExprClass.Variable;
8867 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8869 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8870 ec.Report.Error (190, loc,
8871 "The __arglist construct is valid only within a variable argument method");
8877 public override void Emit (EmitContext ec)
8879 ec.Emit (OpCodes.Arglist);
8882 public override object Accept (StructuralVisitor visitor)
8884 return visitor.Visit (this);
8889 /// Represents the `__arglist (....)' construct
8891 public class Arglist : Expression
8893 Arguments arguments;
8895 public Arglist (Location loc)
8900 public Arglist (Arguments args, Location l)
8906 public Arguments Arguments {
8912 public MetaType[] ArgumentTypes {
8914 if (arguments == null)
8915 return MetaType.EmptyTypes;
8917 var retval = new MetaType[arguments.Count];
8918 for (int i = 0; i < retval.Length; i++)
8919 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8925 public override bool ContainsEmitWithAwait ()
8927 throw new NotImplementedException ();
8930 public override Expression CreateExpressionTree (ResolveContext ec)
8932 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8936 protected override Expression DoResolve (ResolveContext ec)
8938 eclass = ExprClass.Variable;
8939 type = InternalType.Arglist;
8940 if (arguments != null) {
8941 bool dynamic; // Can be ignored as there is always only 1 overload
8942 arguments.Resolve (ec, out dynamic);
8948 public override void Emit (EmitContext ec)
8950 if (arguments != null)
8951 arguments.Emit (ec);
8954 protected override void CloneTo (CloneContext clonectx, Expression t)
8956 Arglist target = (Arglist) t;
8958 if (arguments != null)
8959 target.arguments = arguments.Clone (clonectx);
8962 public override object Accept (StructuralVisitor visitor)
8964 return visitor.Visit (this);
8968 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8970 FullNamedExpression texpr;
8972 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8979 public FullNamedExpression TypeExpression {
8985 public override bool ContainsEmitWithAwait ()
8990 public void AddressOf (EmitContext ec, AddressOp mode)
8993 ec.Emit (OpCodes.Refanyval, type);
8996 protected override Expression DoResolve (ResolveContext rc)
8998 expr = expr.Resolve (rc);
8999 type = texpr.ResolveAsType (rc);
9000 if (expr == null || type == null)
9003 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9004 eclass = ExprClass.Variable;
9008 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9010 return DoResolve (rc);
9013 public override void Emit (EmitContext ec)
9016 ec.Emit (OpCodes.Refanyval, type);
9017 ec.EmitLoadFromPtr (type);
9020 public void Emit (EmitContext ec, bool leave_copy)
9022 throw new NotImplementedException ();
9025 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9028 ec.Emit (OpCodes.Refanyval, type);
9031 LocalTemporary temporary = null;
9033 ec.Emit (OpCodes.Dup);
9034 temporary = new LocalTemporary (source.Type);
9035 temporary.Store (ec);
9038 ec.EmitStoreFromPtr (type);
9040 if (temporary != null) {
9041 temporary.Emit (ec);
9042 temporary.Release (ec);
9046 public override object Accept (StructuralVisitor visitor)
9048 return visitor.Visit (this);
9052 public class RefTypeExpr : ShimExpression
9054 public RefTypeExpr (Expression expr, Location loc)
9060 protected override Expression DoResolve (ResolveContext rc)
9062 expr = expr.Resolve (rc);
9066 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9070 type = rc.BuiltinTypes.Type;
9071 eclass = ExprClass.Value;
9075 public override void Emit (EmitContext ec)
9078 ec.Emit (OpCodes.Refanytype);
9079 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9081 ec.Emit (OpCodes.Call, m);
9084 public override object Accept (StructuralVisitor visitor)
9086 return visitor.Visit (this);
9090 public class MakeRefExpr : ShimExpression
9092 public MakeRefExpr (Expression expr, Location loc)
9098 public override bool ContainsEmitWithAwait ()
9100 throw new NotImplementedException ();
9103 protected override Expression DoResolve (ResolveContext rc)
9105 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9106 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9107 eclass = ExprClass.Value;
9111 public override void Emit (EmitContext ec)
9113 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9114 ec.Emit (OpCodes.Mkrefany, expr.Type);
9117 public override object Accept (StructuralVisitor visitor)
9119 return visitor.Visit (this);
9124 /// Implements the typeof operator
9126 public class TypeOf : Expression {
9127 FullNamedExpression QueriedType;
9130 public TypeOf (FullNamedExpression queried_type, Location l)
9132 QueriedType = queried_type;
9137 // Use this constructor for any compiler generated typeof expression
9139 public TypeOf (TypeSpec type, Location loc)
9141 this.typearg = type;
9147 public override bool IsSideEffectFree {
9153 public TypeSpec TypeArgument {
9159 public FullNamedExpression TypeExpression {
9168 protected override void CloneTo (CloneContext clonectx, Expression t)
9170 TypeOf target = (TypeOf) t;
9171 if (QueriedType != null)
9172 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9175 public override bool ContainsEmitWithAwait ()
9180 public override Expression CreateExpressionTree (ResolveContext ec)
9182 Arguments args = new Arguments (2);
9183 args.Add (new Argument (this));
9184 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9185 return CreateExpressionFactoryCall (ec, "Constant", args);
9188 protected override Expression DoResolve (ResolveContext ec)
9190 if (eclass != ExprClass.Unresolved)
9193 if (typearg == null) {
9195 // Pointer types are allowed without explicit unsafe, they are just tokens
9197 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9198 typearg = QueriedType.ResolveAsType (ec, true);
9201 if (typearg == null)
9204 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9205 ec.Report.Error (1962, QueriedType.Location,
9206 "The typeof operator cannot be used on the dynamic type");
9210 type = ec.BuiltinTypes.Type;
9212 // Even though what is returned is a type object, it's treated as a value by the compiler.
9213 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9214 eclass = ExprClass.Value;
9218 static bool ContainsDynamicType (TypeSpec type)
9220 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9223 var element_container = type as ElementTypeSpec;
9224 if (element_container != null)
9225 return ContainsDynamicType (element_container.Element);
9227 foreach (var t in type.TypeArguments) {
9228 if (ContainsDynamicType (t)) {
9236 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9238 // Target type is not System.Type therefore must be object
9239 // and we need to use different encoding sequence
9240 if (targetType != type)
9243 if (typearg is InflatedTypeSpec) {
9246 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9247 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9248 typearg.GetSignatureForError ());
9252 gt = gt.DeclaringType;
9253 } while (gt != null);
9256 if (ContainsDynamicType (typearg)) {
9257 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9261 enc.EncodeTypeName (typearg);
9264 public override void Emit (EmitContext ec)
9266 ec.Emit (OpCodes.Ldtoken, typearg);
9267 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9269 ec.Emit (OpCodes.Call, m);
9272 public override object Accept (StructuralVisitor visitor)
9274 return visitor.Visit (this);
9278 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9280 public TypeOfMethod (MethodSpec method, Location loc)
9281 : base (method, loc)
9285 protected override Expression DoResolve (ResolveContext ec)
9287 if (member.IsConstructor) {
9288 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9290 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9296 return base.DoResolve (ec);
9299 public override void Emit (EmitContext ec)
9301 ec.Emit (OpCodes.Ldtoken, member);
9304 ec.Emit (OpCodes.Castclass, type);
9307 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9309 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9312 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9314 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9318 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9320 protected readonly T member;
9322 protected TypeOfMember (T member, Location loc)
9324 this.member = member;
9328 public override bool IsSideEffectFree {
9334 public override bool ContainsEmitWithAwait ()
9339 public override Expression CreateExpressionTree (ResolveContext ec)
9341 Arguments args = new Arguments (2);
9342 args.Add (new Argument (this));
9343 args.Add (new Argument (new TypeOf (type, loc)));
9344 return CreateExpressionFactoryCall (ec, "Constant", args);
9347 protected override Expression DoResolve (ResolveContext ec)
9349 eclass = ExprClass.Value;
9353 public override void Emit (EmitContext ec)
9355 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9356 PredefinedMember<MethodSpec> p;
9358 p = GetTypeFromHandleGeneric (ec);
9359 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9361 p = GetTypeFromHandle (ec);
9364 var mi = p.Resolve (loc);
9366 ec.Emit (OpCodes.Call, mi);
9369 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9370 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9373 sealed class TypeOfField : TypeOfMember<FieldSpec>
9375 public TypeOfField (FieldSpec field, Location loc)
9380 protected override Expression DoResolve (ResolveContext ec)
9382 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9386 return base.DoResolve (ec);
9389 public override void Emit (EmitContext ec)
9391 ec.Emit (OpCodes.Ldtoken, member);
9395 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9397 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9400 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9402 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9407 /// Implements the sizeof expression
9409 public class SizeOf : Expression {
9410 readonly Expression texpr;
9411 TypeSpec type_queried;
9413 public SizeOf (Expression queried_type, Location l)
9415 this.texpr = queried_type;
9419 public override bool IsSideEffectFree {
9425 public Expression TypeExpression {
9431 public override bool ContainsEmitWithAwait ()
9436 public override Expression CreateExpressionTree (ResolveContext ec)
9438 Error_PointerInsideExpressionTree (ec);
9442 protected override Expression DoResolve (ResolveContext ec)
9444 type_queried = texpr.ResolveAsType (ec);
9445 if (type_queried == null)
9448 if (type_queried.IsEnum)
9449 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9451 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9453 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9456 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9461 ec.Report.Error (233, loc,
9462 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9463 type_queried.GetSignatureForError ());
9466 type = ec.BuiltinTypes.Int;
9467 eclass = ExprClass.Value;
9471 public override void Emit (EmitContext ec)
9473 ec.Emit (OpCodes.Sizeof, type_queried);
9476 protected override void CloneTo (CloneContext clonectx, Expression t)
9480 public override object Accept (StructuralVisitor visitor)
9482 return visitor.Visit (this);
9487 /// Implements the qualified-alias-member (::) expression.
9489 public class QualifiedAliasMember : MemberAccess
9491 readonly string alias;
9492 public static readonly string GlobalAlias = "global";
9494 public QualifiedAliasMember (string alias, string identifier, Location l)
9495 : base (null, identifier, l)
9500 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9501 : base (null, identifier, targs, l)
9506 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9507 : base (null, identifier, arity, l)
9512 public string Alias {
9518 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9520 if (alias == GlobalAlias)
9521 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9523 int errors = mc.Module.Compiler.Report.Errors;
9524 var expr = mc.LookupNamespaceAlias (alias);
9526 if (errors == mc.Module.Compiler.Report.Errors)
9527 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9535 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9537 expr = CreateExpressionFromAlias (mc);
9541 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9544 protected override Expression DoResolve (ResolveContext rc)
9546 return ResolveAsTypeOrNamespace (rc, false);
9549 public override string GetSignatureForError ()
9552 if (targs != null) {
9553 name = Name + "<" + targs.GetSignatureForError () + ">";
9556 return alias + "::" + name;
9559 public override bool HasConditionalAccess ()
9564 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9566 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9567 rc.Module.Compiler.Report.Error (687, loc,
9568 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9569 GetSignatureForError ());
9574 return DoResolve (rc);
9577 protected override void CloneTo (CloneContext clonectx, Expression t)
9582 public override object Accept (StructuralVisitor visitor)
9584 return visitor.Visit (this);
9589 /// Implements the member access expression
9591 public class MemberAccess : ATypeNameExpression
9593 protected Expression expr;
9595 public MemberAccess (Expression expr, string id)
9596 : base (id, expr.Location)
9601 public MemberAccess (Expression expr, string identifier, Location loc)
9602 : base (identifier, loc)
9607 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9608 : base (identifier, args, loc)
9613 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9614 : base (identifier, arity, loc)
9619 public Expression LeftExpression {
9625 public override Location StartLocation {
9627 return expr == null ? loc : expr.StartLocation;
9631 protected override Expression DoResolve (ResolveContext rc)
9633 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9635 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9640 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9642 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9644 if (e is TypeExpr) {
9645 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9650 e = e.ResolveLValue (rc, rhs);
9655 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9657 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9658 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9660 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9663 public override bool HasConditionalAccess ()
9665 return LeftExpression.HasConditionalAccess ();
9668 public static bool IsValidDotExpression (TypeSpec type)
9670 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9671 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9673 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9676 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9678 var sn = expr as SimpleName;
9679 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9682 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9685 // Resolve expression which does have type set as we need expression type
9686 // with disable flow analysis as we don't know whether left side expression
9687 // is used as variable or type
9689 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9690 expr = expr.Resolve (rc);
9691 } else if (expr is TypeParameterExpr) {
9692 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9696 bool resolved = false;
9697 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
9698 if (expr.HasConditionalAccess ()) {
9700 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9701 expr = expr.Resolve (rc, flags);
9707 expr = expr.Resolve (rc, flags);
9713 var ns = expr as NamespaceExpression;
9715 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9717 if (retval == null) {
9718 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9723 if (HasTypeArguments)
9724 return new GenericTypeExpr (retval.Type, targs, loc);
9726 targs.Resolve (rc, false);
9733 TypeSpec expr_type = expr.Type;
9734 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9735 me = expr as MemberExpr;
9737 me.ResolveInstanceExpression (rc, null);
9739 Arguments args = new Arguments (1);
9740 args.Add (new Argument (expr));
9741 return new DynamicMemberBinder (Name, args, loc);
9744 var cma = this as ConditionalMemberAccess;
9746 if (!IsNullPropagatingValid (expr.Type)) {
9747 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9751 if (expr_type.IsNullableType) {
9752 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9753 expr_type = expr.Type;
9757 if (!IsValidDotExpression (expr_type)) {
9758 Error_OperatorCannotBeApplied (rc, expr_type);
9762 var lookup_arity = Arity;
9763 bool errorMode = false;
9764 Expression member_lookup;
9766 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9767 if (member_lookup == null) {
9769 // Try to look for extension method when member lookup failed
9771 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9772 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9773 if (methods != null) {
9774 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9775 if (HasTypeArguments) {
9776 if (!targs.Resolve (rc, false))
9779 emg.SetTypeArguments (rc, targs);
9783 emg.ConditionalAccess = true;
9785 // TODO: it should really skip the checks bellow
9786 return emg.Resolve (rc);
9792 if (member_lookup == null) {
9793 var dep = expr_type.GetMissingDependencies ();
9795 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9796 } else if (expr is TypeExpr) {
9797 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9799 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9805 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9806 // Leave it to overload resolution to report correct error
9807 } else if (!(member_lookup is TypeExpr)) {
9808 // TODO: rc.SymbolRelatedToPreviousError
9809 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9814 if (member_lookup != null)
9818 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9822 TypeExpr texpr = member_lookup as TypeExpr;
9823 if (texpr != null) {
9824 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9825 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9826 Name, texpr.GetSignatureForError ());
9829 if (!texpr.Type.IsAccessible (rc)) {
9830 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9831 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9835 if (HasTypeArguments) {
9836 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9839 return member_lookup;
9842 me = member_lookup as MemberExpr;
9844 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9849 me.ConditionalAccess = true;
9852 me = me.ResolveMemberAccess (rc, expr, sn);
9855 if (!targs.Resolve (rc, false))
9858 me.SetTypeArguments (rc, targs);
9864 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9866 FullNamedExpression fexpr = expr as FullNamedExpression;
9867 if (fexpr == null) {
9868 expr.ResolveAsType (rc);
9872 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9874 if (expr_resolved == null)
9877 var ns = expr_resolved as NamespaceExpression;
9879 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9881 if (retval == null) {
9882 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9883 } else if (Arity > 0) {
9884 if (HasTypeArguments) {
9885 retval = new GenericTypeExpr (retval.Type, targs, loc);
9886 if (retval.ResolveAsType (rc) == null)
9889 targs.Resolve (rc, allowUnboundTypeArguments);
9891 retval = new GenericOpenTypeExpr (retval.Type, loc);
9898 var tnew_expr = expr_resolved.ResolveAsType (rc);
9899 if (tnew_expr == null)
9902 TypeSpec expr_type = tnew_expr;
9903 if (TypeManager.IsGenericParameter (expr_type)) {
9904 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9905 tnew_expr.GetSignatureForError ());
9909 var qam = this as QualifiedAliasMember;
9911 rc.Module.Compiler.Report.Error (431, loc,
9912 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9917 TypeSpec nested = null;
9918 while (expr_type != null) {
9919 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9920 if (nested == null) {
9921 if (expr_type == tnew_expr) {
9922 Error_IdentifierNotFound (rc, expr_type);
9926 expr_type = tnew_expr;
9927 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9928 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9932 if (nested.IsAccessible (rc))
9936 // Keep looking after inaccessible candidate but only if
9937 // we are not in same context as the definition itself
9939 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9942 expr_type = expr_type.BaseType;
9947 if (HasTypeArguments) {
9948 texpr = new GenericTypeExpr (nested, targs, loc);
9950 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9952 texpr = new GenericOpenTypeExpr (nested, loc);
9954 } else if (expr_resolved is GenericOpenTypeExpr) {
9955 texpr = new GenericOpenTypeExpr (nested, loc);
9957 texpr = new TypeExpression (nested, loc);
9960 if (texpr.ResolveAsType (rc) == null)
9966 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9968 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9970 if (nested != null) {
9971 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9975 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9976 if (any_other_member != null) {
9977 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9981 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9982 Name, expr_type.GetSignatureForError ());
9985 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9987 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9990 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9992 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9993 ec.Report.SymbolRelatedToPreviousError (type);
9995 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9997 // a using directive or an assembly reference
9999 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10001 missing = "an assembly reference";
10004 ec.Report.Error (1061, loc,
10005 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10006 type.GetSignatureForError (), name, missing);
10010 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10013 public override string GetSignatureForError ()
10015 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10018 protected override void CloneTo (CloneContext clonectx, Expression t)
10020 MemberAccess target = (MemberAccess) t;
10022 target.expr = expr.Clone (clonectx);
10025 public override object Accept (StructuralVisitor visitor)
10027 return visitor.Visit (this);
10031 public class ConditionalMemberAccess : MemberAccess
10033 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10034 : base (expr, identifier, args, loc)
10038 public override bool HasConditionalAccess ()
10045 /// Implements checked expressions
10047 public class CheckedExpr : Expression {
10049 public Expression Expr;
10051 public CheckedExpr (Expression e, Location l)
10057 public override bool ContainsEmitWithAwait ()
10059 return Expr.ContainsEmitWithAwait ();
10062 public override Expression CreateExpressionTree (ResolveContext ec)
10064 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10065 return Expr.CreateExpressionTree (ec);
10068 protected override Expression DoResolve (ResolveContext ec)
10070 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10071 Expr = Expr.Resolve (ec);
10076 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10079 eclass = Expr.eclass;
10084 public override void Emit (EmitContext ec)
10086 using (ec.With (EmitContext.Options.CheckedScope, true))
10090 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10092 using (ec.With (EmitContext.Options.CheckedScope, true))
10093 Expr.EmitBranchable (ec, target, on_true);
10096 public override void FlowAnalysis (FlowAnalysisContext fc)
10098 Expr.FlowAnalysis (fc);
10101 public override SLE.Expression MakeExpression (BuilderContext ctx)
10103 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10104 return Expr.MakeExpression (ctx);
10108 protected override void CloneTo (CloneContext clonectx, Expression t)
10110 CheckedExpr target = (CheckedExpr) t;
10112 target.Expr = Expr.Clone (clonectx);
10115 public override object Accept (StructuralVisitor visitor)
10117 return visitor.Visit (this);
10122 /// Implements the unchecked expression
10124 public class UnCheckedExpr : Expression {
10126 public Expression Expr;
10128 public UnCheckedExpr (Expression e, Location l)
10134 public override bool ContainsEmitWithAwait ()
10136 return Expr.ContainsEmitWithAwait ();
10139 public override Expression CreateExpressionTree (ResolveContext ec)
10141 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10142 return Expr.CreateExpressionTree (ec);
10145 protected override Expression DoResolve (ResolveContext ec)
10147 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10148 Expr = Expr.Resolve (ec);
10153 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10156 eclass = Expr.eclass;
10161 public override void Emit (EmitContext ec)
10163 using (ec.With (EmitContext.Options.CheckedScope, false))
10167 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10169 using (ec.With (EmitContext.Options.CheckedScope, false))
10170 Expr.EmitBranchable (ec, target, on_true);
10173 public override void FlowAnalysis (FlowAnalysisContext fc)
10175 Expr.FlowAnalysis (fc);
10178 protected override void CloneTo (CloneContext clonectx, Expression t)
10180 UnCheckedExpr target = (UnCheckedExpr) t;
10182 target.Expr = Expr.Clone (clonectx);
10185 public override object Accept (StructuralVisitor visitor)
10187 return visitor.Visit (this);
10192 /// An Element Access expression.
10194 /// During semantic analysis these are transformed into
10195 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10197 public class ElementAccess : Expression
10199 public Arguments Arguments;
10200 public Expression Expr;
10202 public ElementAccess (Expression e, Arguments args, Location loc)
10206 this.Arguments = args;
10209 public bool ConditionalAccess { get; set; }
10211 public override Location StartLocation {
10213 return Expr.StartLocation;
10217 public override bool ContainsEmitWithAwait ()
10219 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10223 // We perform some simple tests, and then to "split" the emit and store
10224 // code we create an instance of a different class, and return that.
10226 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10228 Expr = Expr.Resolve (ec);
10234 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10235 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10240 return new ArrayAccess (this, loc) {
10241 ConditionalAccess = ConditionalAccess,
10242 ConditionalAccessReceiver = conditionalAccessReceiver
10245 if (type.IsPointer)
10246 return Expr.MakePointerAccess (ec, type, Arguments);
10248 FieldExpr fe = Expr as FieldExpr;
10250 var ff = fe.Spec as FixedFieldSpec;
10252 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10256 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10257 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10258 var indexer = new IndexerExpr (indexers, type, this) {
10259 ConditionalAccess = ConditionalAccess
10262 if (conditionalAccessReceiver)
10263 indexer.SetConditionalAccessReceiver ();
10268 Error_CannotApplyIndexing (ec, type, loc);
10273 public override Expression CreateExpressionTree (ResolveContext ec)
10275 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10276 Expr.CreateExpressionTree (ec));
10278 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10281 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10283 if (type != InternalType.ErrorType) {
10284 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10285 type.GetSignatureForError ());
10289 public override bool HasConditionalAccess ()
10291 return ConditionalAccess || Expr.HasConditionalAccess ();
10294 protected override Expression DoResolve (ResolveContext rc)
10297 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10298 if (HasConditionalAccess ()) {
10299 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10300 expr = CreateAccessExpression (rc, true);
10304 return expr.Resolve (rc);
10309 expr = CreateAccessExpression (rc, false);
10313 return expr.Resolve (rc);
10316 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10318 var res = CreateAccessExpression (ec, false);
10322 return res.ResolveLValue (ec, rhs);
10325 public override void Emit (EmitContext ec)
10327 throw new Exception ("Should never be reached");
10330 public override void FlowAnalysis (FlowAnalysisContext fc)
10332 Expr.FlowAnalysis (fc);
10334 if (ConditionalAccess)
10335 fc.BranchConditionalAccessDefiniteAssignment ();
10337 Arguments.FlowAnalysis (fc);
10340 public override string GetSignatureForError ()
10342 return Expr.GetSignatureForError ();
10345 protected override void CloneTo (CloneContext clonectx, Expression t)
10347 ElementAccess target = (ElementAccess) t;
10349 target.Expr = Expr.Clone (clonectx);
10350 if (Arguments != null)
10351 target.Arguments = Arguments.Clone (clonectx);
10354 public override object Accept (StructuralVisitor visitor)
10356 return visitor.Visit (this);
10361 /// Implements array access
10363 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10365 // Points to our "data" repository
10369 LocalTemporary temp;
10371 bool? has_await_args;
10373 public ArrayAccess (ElementAccess ea_data, Location l)
10379 public bool ConditionalAccess { get; set; }
10381 public bool ConditionalAccessReceiver { get; set; }
10383 public void AddressOf (EmitContext ec, AddressOp mode)
10385 var ac = (ArrayContainer) ea.Expr.Type;
10387 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10388 LoadInstanceAndArguments (ec, false, true);
10391 LoadInstanceAndArguments (ec, false, false);
10393 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10394 ec.Emit (OpCodes.Readonly);
10396 ec.EmitArrayAddress (ac);
10399 public override Expression CreateExpressionTree (ResolveContext ec)
10401 if (ConditionalAccess)
10402 Error_NullShortCircuitInsideExpressionTree (ec);
10404 return ea.CreateExpressionTree (ec);
10407 public override bool ContainsEmitWithAwait ()
10409 return ea.ContainsEmitWithAwait ();
10412 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10414 if (HasConditionalAccess ())
10415 Error_NullPropagatingLValue (ec);
10417 return DoResolve (ec);
10420 protected override Expression DoResolve (ResolveContext ec)
10422 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10424 ea.Arguments.Resolve (ec, out dynamic);
10426 var ac = ea.Expr.Type as ArrayContainer;
10427 int rank = ea.Arguments.Count;
10428 if (ac.Rank != rank) {
10429 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10430 rank.ToString (), ac.Rank.ToString ());
10435 if (type.IsPointer && !ec.IsUnsafe) {
10436 UnsafeError (ec, ea.Location);
10439 if (ConditionalAccessReceiver)
10440 type = LiftMemberType (ec, type);
10442 foreach (Argument a in ea.Arguments) {
10443 var na = a as NamedArgument;
10445 ElementAccess.Error_NamedArgument (na, ec.Report);
10447 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10450 eclass = ExprClass.Variable;
10455 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10457 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10460 public override void FlowAnalysis (FlowAnalysisContext fc)
10462 ea.FlowAnalysis (fc);
10465 public override bool HasConditionalAccess ()
10467 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10471 // Load the array arguments into the stack.
10473 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10475 if (prepareAwait) {
10476 ea.Expr = ea.Expr.EmitToField (ec);
10478 var ie = new InstanceEmitter (ea.Expr, false);
10479 ie.Emit (ec, ConditionalAccess);
10481 if (duplicateArguments) {
10482 ec.Emit (OpCodes.Dup);
10484 var copy = new LocalTemporary (ea.Expr.Type);
10490 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10491 if (dup_args != null)
10492 ea.Arguments = dup_args;
10495 public void Emit (EmitContext ec, bool leave_copy)
10498 ec.EmitLoadFromPtr (type);
10500 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10501 LoadInstanceAndArguments (ec, false, true);
10504 if (ConditionalAccessReceiver)
10505 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10507 var ac = (ArrayContainer) ea.Expr.Type;
10508 LoadInstanceAndArguments (ec, false, false);
10509 ec.EmitArrayLoad (ac);
10511 if (ConditionalAccessReceiver)
10512 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10516 ec.Emit (OpCodes.Dup);
10517 temp = new LocalTemporary (this.type);
10522 public override void Emit (EmitContext ec)
10527 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10529 var ac = (ArrayContainer) ea.Expr.Type;
10530 TypeSpec t = source.Type;
10532 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10535 // When we are dealing with a struct, get the address of it to avoid value copy
10536 // Same cannot be done for reference type because array covariance and the
10537 // check in ldelema requires to specify the type of array element stored at the index
10539 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10540 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10542 if (has_await_args.Value) {
10543 if (source.ContainsEmitWithAwait ()) {
10544 source = source.EmitToField (ec);
10545 isCompound = false;
10549 LoadInstanceAndArguments (ec, isCompound, false);
10554 ec.EmitArrayAddress (ac);
10557 ec.Emit (OpCodes.Dup);
10561 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10563 if (has_await_args.Value) {
10564 if (source.ContainsEmitWithAwait ())
10565 source = source.EmitToField (ec);
10567 LoadInstanceAndArguments (ec, false, false);
10574 var lt = ea.Expr as LocalTemporary;
10580 ec.Emit (OpCodes.Dup);
10581 temp = new LocalTemporary (this.type);
10586 ec.EmitStoreFromPtr (t);
10588 ec.EmitArrayStore (ac);
10591 if (temp != null) {
10597 public override Expression EmitToField (EmitContext ec)
10600 // Have to be specialized for arrays to get access to
10601 // underlying element. Instead of another result copy we
10602 // need direct access to element
10606 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10608 ea.Expr = ea.Expr.EmitToField (ec);
10609 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10613 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10615 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10618 public override SLE.Expression MakeExpression (BuilderContext ctx)
10620 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10623 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10625 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10626 return Arguments.MakeExpression (ea.Arguments, ctx);
10632 // Indexer access expression
10634 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10636 IList<MemberSpec> indexers;
10637 Arguments arguments;
10638 TypeSpec queried_type;
10640 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10641 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10645 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10648 this.indexers = indexers;
10649 this.queried_type = queriedType;
10650 this.InstanceExpression = instance;
10651 this.arguments = args;
10656 protected override Arguments Arguments {
10665 protected override TypeSpec DeclaringType {
10667 return best_candidate.DeclaringType;
10671 public override bool IsInstance {
10677 public override bool IsStatic {
10683 public override string KindName {
10684 get { return "indexer"; }
10687 public override string Name {
10695 public override bool ContainsEmitWithAwait ()
10697 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10700 public override Expression CreateExpressionTree (ResolveContext ec)
10702 if (ConditionalAccess) {
10703 Error_NullShortCircuitInsideExpressionTree (ec);
10706 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10707 InstanceExpression.CreateExpressionTree (ec),
10708 new TypeOfMethod (Getter, loc));
10710 return CreateExpressionFactoryCall (ec, "Call", args);
10713 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10715 LocalTemporary await_source_arg = null;
10718 emitting_compound_assignment = true;
10719 if (source is DynamicExpressionStatement) {
10724 emitting_compound_assignment = false;
10726 if (has_await_arguments) {
10727 await_source_arg = new LocalTemporary (Type);
10728 await_source_arg.Store (ec);
10730 arguments.Add (new Argument (await_source_arg));
10733 temp = await_source_arg;
10736 has_await_arguments = false;
10741 ec.Emit (OpCodes.Dup);
10742 temp = new LocalTemporary (Type);
10748 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10749 source = source.EmitToField (ec);
10751 temp = new LocalTemporary (Type);
10758 arguments.Add (new Argument (source));
10761 var call = new CallEmitter ();
10762 call.InstanceExpression = InstanceExpression;
10763 if (arguments == null)
10764 call.InstanceExpressionOnStack = true;
10766 call.Emit (ec, Setter, arguments, loc);
10768 if (temp != null) {
10771 } else if (leave_copy) {
10775 if (await_source_arg != null) {
10776 await_source_arg.Release (ec);
10780 public override void FlowAnalysis (FlowAnalysisContext fc)
10782 base.FlowAnalysis (fc);
10783 arguments.FlowAnalysis (fc);
10785 if (conditional_access_receiver)
10786 fc.ConditionalAccessEnd ();
10789 public override string GetSignatureForError ()
10791 return best_candidate.GetSignatureForError ();
10794 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10797 throw new NotSupportedException ();
10799 var value = new[] { source.MakeExpression (ctx) };
10800 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10801 return SLE.Expression.Block (
10802 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10807 public override SLE.Expression MakeExpression (BuilderContext ctx)
10810 return base.MakeExpression (ctx);
10812 var args = Arguments.MakeExpression (arguments, ctx);
10813 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10817 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10819 if (best_candidate != null)
10822 eclass = ExprClass.IndexerAccess;
10825 arguments.Resolve (rc, out dynamic);
10827 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10830 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10831 res.BaseMembersProvider = this;
10832 res.InstanceQualifier = this;
10834 // TODO: Do I need 2 argument sets?
10835 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10836 if (best_candidate != null)
10837 type = res.BestCandidateReturnType;
10838 else if (!res.BestCandidateIsDynamic)
10843 // It has dynamic arguments
10846 Arguments args = new Arguments (arguments.Count + 1);
10848 rc.Report.Error (1972, loc,
10849 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10851 args.Add (new Argument (InstanceExpression));
10853 args.AddRange (arguments);
10855 best_candidate = null;
10856 return new DynamicIndexBinder (args, loc);
10860 // Try to avoid resolving left expression again
10862 if (right_side != null)
10863 ResolveInstanceExpression (rc, right_side);
10868 protected override void CloneTo (CloneContext clonectx, Expression t)
10870 IndexerExpr target = (IndexerExpr) t;
10872 if (arguments != null)
10873 target.arguments = arguments.Clone (clonectx);
10876 public void SetConditionalAccessReceiver ()
10878 conditional_access_receiver = true;
10881 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10883 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10886 #region IBaseMembersProvider Members
10888 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10890 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10893 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10895 if (queried_type == member.DeclaringType)
10898 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10899 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10902 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10911 // A base access expression
10913 public class BaseThis : This
10915 public BaseThis (Location loc)
10920 public BaseThis (TypeSpec type, Location loc)
10924 eclass = ExprClass.Variable;
10929 public override string Name {
10937 public override Expression CreateExpressionTree (ResolveContext ec)
10939 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10940 return base.CreateExpressionTree (ec);
10943 public override void Emit (EmitContext ec)
10947 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10948 var context_type = ec.CurrentType;
10949 ec.Emit (OpCodes.Ldobj, context_type);
10950 ec.Emit (OpCodes.Box, context_type);
10954 protected override void Error_ThisNotAvailable (ResolveContext ec)
10957 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10959 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10963 public override void ResolveBase (ResolveContext ec)
10965 base.ResolveBase (ec);
10966 type = ec.CurrentType.BaseType;
10969 public override object Accept (StructuralVisitor visitor)
10971 return visitor.Visit (this);
10976 /// This class exists solely to pass the Type around and to be a dummy
10977 /// that can be passed to the conversion functions (this is used by
10978 /// foreach implementation to typecast the object return value from
10979 /// get_Current into the proper type. All code has been generated and
10980 /// we only care about the side effect conversions to be performed
10982 /// This is also now used as a placeholder where a no-action expression
10983 /// is needed (the `New' class).
10985 public class EmptyExpression : Expression
10987 sealed class OutAccessExpression : EmptyExpression
10989 public OutAccessExpression (TypeSpec t)
10994 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10996 rc.Report.Error (206, right_side.Location,
10997 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11003 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11004 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11005 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11006 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11007 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11008 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11009 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11010 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11012 public EmptyExpression (TypeSpec t)
11015 eclass = ExprClass.Value;
11016 loc = Location.Null;
11019 protected override void CloneTo (CloneContext clonectx, Expression target)
11023 public override bool ContainsEmitWithAwait ()
11028 public override Expression CreateExpressionTree (ResolveContext ec)
11030 throw new NotSupportedException ("ET");
11033 protected override Expression DoResolve (ResolveContext ec)
11038 public override void Emit (EmitContext ec)
11040 // nothing, as we only exist to not do anything.
11043 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11047 public override void EmitSideEffect (EmitContext ec)
11051 public override object Accept (StructuralVisitor visitor)
11053 return visitor.Visit (this);
11057 sealed class EmptyAwaitExpression : EmptyExpression
11059 public EmptyAwaitExpression (TypeSpec type)
11064 public override bool ContainsEmitWithAwait ()
11071 // Empty statement expression
11073 public sealed class EmptyExpressionStatement : ExpressionStatement
11075 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11077 private EmptyExpressionStatement ()
11079 loc = Location.Null;
11082 public override bool ContainsEmitWithAwait ()
11087 public override Expression CreateExpressionTree (ResolveContext ec)
11092 public override void EmitStatement (EmitContext ec)
11097 protected override Expression DoResolve (ResolveContext ec)
11099 eclass = ExprClass.Value;
11100 type = ec.BuiltinTypes.Object;
11104 public override void Emit (EmitContext ec)
11109 public override object Accept (StructuralVisitor visitor)
11111 return visitor.Visit (this);
11115 public class ErrorExpression : EmptyExpression
11117 public static readonly ErrorExpression Instance = new ErrorExpression ();
11119 private ErrorExpression ()
11120 : base (InternalType.ErrorType)
11124 public override Expression CreateExpressionTree (ResolveContext ec)
11129 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11134 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11138 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11142 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11146 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11150 public override object Accept (StructuralVisitor visitor)
11152 return visitor.Visit (this);
11156 public class UserCast : Expression {
11160 public UserCast (MethodSpec method, Expression source, Location l)
11162 if (source == null)
11163 throw new ArgumentNullException ("source");
11165 this.method = method;
11166 this.source = source;
11167 type = method.ReturnType;
11171 public Expression Source {
11180 public override bool ContainsEmitWithAwait ()
11182 return source.ContainsEmitWithAwait ();
11185 public override Expression CreateExpressionTree (ResolveContext ec)
11187 Arguments args = new Arguments (3);
11188 args.Add (new Argument (source.CreateExpressionTree (ec)));
11189 args.Add (new Argument (new TypeOf (type, loc)));
11190 args.Add (new Argument (new TypeOfMethod (method, loc)));
11191 return CreateExpressionFactoryCall (ec, "Convert", args);
11194 protected override Expression DoResolve (ResolveContext ec)
11196 method.CheckObsoleteness (ec, source.Location);
11198 eclass = ExprClass.Value;
11202 public override void Emit (EmitContext ec)
11205 ec.MarkCallEntry (loc);
11206 ec.Emit (OpCodes.Call, method);
11209 public override void FlowAnalysis (FlowAnalysisContext fc)
11211 source.FlowAnalysis (fc);
11214 public override string GetSignatureForError ()
11216 return TypeManager.CSharpSignature (method);
11219 public override SLE.Expression MakeExpression (BuilderContext ctx)
11222 return base.MakeExpression (ctx);
11224 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11230 // Holds additional type specifiers like ?, *, []
11232 public class ComposedTypeSpecifier
11234 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11236 public readonly int Dimension;
11237 public readonly Location Location;
11239 public ComposedTypeSpecifier (int specifier, Location loc)
11241 this.Dimension = specifier;
11242 this.Location = loc;
11246 public bool IsNullable {
11248 return Dimension == -1;
11252 public bool IsPointer {
11254 return Dimension == -2;
11258 public ComposedTypeSpecifier Next { get; set; }
11262 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11264 return new ComposedTypeSpecifier (dimension, loc);
11267 public static ComposedTypeSpecifier CreateNullable (Location loc)
11269 return new ComposedTypeSpecifier (-1, loc);
11272 public static ComposedTypeSpecifier CreatePointer (Location loc)
11274 return new ComposedTypeSpecifier (-2, loc);
11277 public string GetSignatureForError ()
11282 ArrayContainer.GetPostfixSignature (Dimension);
11284 return Next != null ? s + Next.GetSignatureForError () : s;
11289 // This class is used to "construct" the type during a typecast
11290 // operation. Since the Type.GetType class in .NET can parse
11291 // the type specification, we just use this to construct the type
11292 // one bit at a time.
11294 public class ComposedCast : TypeExpr {
11295 FullNamedExpression left;
11296 ComposedTypeSpecifier spec;
11298 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11301 throw new ArgumentNullException ("spec");
11305 this.loc = left.Location;
11308 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11310 type = left.ResolveAsType (ec);
11314 eclass = ExprClass.Type;
11316 var single_spec = spec;
11318 if (single_spec.IsNullable) {
11319 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11323 single_spec = single_spec.Next;
11324 } else if (single_spec.IsPointer) {
11325 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11328 if (!ec.IsUnsafe) {
11329 UnsafeError (ec.Module.Compiler.Report, loc);
11333 type = PointerContainer.MakeType (ec.Module, type);
11334 single_spec = single_spec.Next;
11335 } while (single_spec != null && single_spec.IsPointer);
11338 if (single_spec != null && single_spec.Dimension > 0) {
11339 if (type.IsSpecialRuntimeType) {
11340 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11341 } else if (type.IsStatic) {
11342 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11343 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11344 type.GetSignatureForError ());
11346 MakeArray (ec.Module, single_spec);
11353 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11355 if (spec.Next != null)
11356 MakeArray (module, spec.Next);
11358 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11361 public override string GetSignatureForError ()
11363 return left.GetSignatureForError () + spec.GetSignatureForError ();
11366 public override object Accept (StructuralVisitor visitor)
11368 return visitor.Visit (this);
11372 class FixedBufferPtr : Expression
11374 readonly Expression array;
11376 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11378 this.type = array_type;
11379 this.array = array;
11383 public override bool ContainsEmitWithAwait ()
11385 throw new NotImplementedException ();
11388 public override Expression CreateExpressionTree (ResolveContext ec)
11390 Error_PointerInsideExpressionTree (ec);
11394 public override void Emit(EmitContext ec)
11399 protected override Expression DoResolve (ResolveContext ec)
11401 type = PointerContainer.MakeType (ec.Module, type);
11402 eclass = ExprClass.Value;
11409 // This class is used to represent the address of an array, used
11410 // only by the Fixed statement, this generates "&a [0]" construct
11411 // for fixed (char *pa = a)
11413 class ArrayPtr : FixedBufferPtr
11415 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11416 base (array, array_type, l)
11420 public override void Emit (EmitContext ec)
11425 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11430 // Encapsulates a conversion rules required for array indexes
11432 public class ArrayIndexCast : TypeCast
11434 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11435 : base (expr, returnType)
11437 if (expr.Type == returnType) // int -> int
11438 throw new ArgumentException ("unnecessary array index conversion");
11441 public override Expression CreateExpressionTree (ResolveContext ec)
11443 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11444 return base.CreateExpressionTree (ec);
11448 public override void Emit (EmitContext ec)
11452 switch (child.Type.BuiltinType) {
11453 case BuiltinTypeSpec.Type.UInt:
11454 ec.Emit (OpCodes.Conv_U);
11456 case BuiltinTypeSpec.Type.Long:
11457 ec.Emit (OpCodes.Conv_Ovf_I);
11459 case BuiltinTypeSpec.Type.ULong:
11460 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11463 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11469 // Implements the `stackalloc' keyword
11471 public class StackAlloc : Expression {
11476 public StackAlloc (Expression type, Expression count, Location l)
11479 this.count = count;
11483 public Expression TypeExpression {
11489 public Expression CountExpression {
11495 public override bool ContainsEmitWithAwait ()
11500 public override Expression CreateExpressionTree (ResolveContext ec)
11502 throw new NotSupportedException ("ET");
11505 protected override Expression DoResolve (ResolveContext ec)
11507 count = count.Resolve (ec);
11511 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11512 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11517 Constant c = count as Constant;
11518 if (c != null && c.IsNegative) {
11519 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11522 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11523 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11526 otype = texpr.ResolveAsType (ec);
11530 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11533 type = PointerContainer.MakeType (ec.Module, otype);
11534 eclass = ExprClass.Value;
11539 public override void Emit (EmitContext ec)
11541 int size = BuiltinTypeSpec.GetSize (otype);
11546 ec.Emit (OpCodes.Sizeof, otype);
11550 ec.Emit (OpCodes.Mul_Ovf_Un);
11551 ec.Emit (OpCodes.Localloc);
11554 protected override void CloneTo (CloneContext clonectx, Expression t)
11556 StackAlloc target = (StackAlloc) t;
11557 target.count = count.Clone (clonectx);
11558 target.texpr = texpr.Clone (clonectx);
11561 public override object Accept (StructuralVisitor visitor)
11563 return visitor.Visit (this);
11568 // An object initializer expression
11570 public class ElementInitializer : Assign
11572 public readonly string Name;
11574 public ElementInitializer (string name, Expression initializer, Location loc)
11575 : base (null, initializer, loc)
11580 public bool IsDictionaryInitializer {
11582 return Name == null;
11586 protected override void CloneTo (CloneContext clonectx, Expression t)
11588 ElementInitializer target = (ElementInitializer) t;
11589 target.source = source.Clone (clonectx);
11592 public override Expression CreateExpressionTree (ResolveContext ec)
11594 Arguments args = new Arguments (2);
11595 FieldExpr fe = target as FieldExpr;
11597 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11599 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11602 Expression arg_expr;
11603 var cinit = source as CollectionOrObjectInitializers;
11604 if (cinit == null) {
11606 arg_expr = source.CreateExpressionTree (ec);
11608 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11609 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11612 args.Add (new Argument (arg_expr));
11613 return CreateExpressionFactoryCall (ec, mname, args);
11616 protected override Expression DoResolve (ResolveContext ec)
11618 if (source == null)
11619 return EmptyExpressionStatement.Instance;
11621 if (!ResolveElement (ec))
11624 if (source is CollectionOrObjectInitializers) {
11625 Expression previous = ec.CurrentInitializerVariable;
11626 ec.CurrentInitializerVariable = target;
11627 source = source.Resolve (ec);
11628 ec.CurrentInitializerVariable = previous;
11629 if (source == null)
11632 eclass = source.eclass;
11633 type = source.Type;
11637 return base.DoResolve (ec);
11640 public override void EmitStatement (EmitContext ec)
11642 if (source is CollectionOrObjectInitializers)
11645 base.EmitStatement (ec);
11648 protected virtual bool ResolveElement (ResolveContext rc)
11650 var t = rc.CurrentInitializerVariable.Type;
11651 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11652 Arguments args = new Arguments (1);
11653 args.Add (new Argument (rc.CurrentInitializerVariable));
11654 target = new DynamicMemberBinder (Name, args, loc);
11657 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11658 if (member == null) {
11659 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11661 if (member != null) {
11662 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11663 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11668 if (member == null) {
11669 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11673 var me = member as MemberExpr;
11674 if (me is EventExpr) {
11675 me = me.ResolveMemberAccess (rc, null, null);
11676 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11677 rc.Report.Error (1913, loc,
11678 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11679 member.GetSignatureForError ());
11685 rc.Report.Error (1914, loc,
11686 "Static field or property `{0}' cannot be assigned in an object initializer",
11687 me.GetSignatureForError ());
11691 me.InstanceExpression = rc.CurrentInitializerVariable;
11699 // A collection initializer expression
11701 class CollectionElementInitializer : Invocation
11703 public class ElementInitializerArgument : Argument
11705 public ElementInitializerArgument (Expression e)
11711 sealed class AddMemberAccess : MemberAccess
11713 public AddMemberAccess (Expression expr, Location loc)
11714 : base (expr, "Add", loc)
11718 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11720 if (TypeManager.HasElementType (type))
11723 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11727 public CollectionElementInitializer (Expression argument)
11728 : base (null, new Arguments (1))
11730 base.arguments.Add (new ElementInitializerArgument (argument));
11731 this.loc = argument.Location;
11734 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11735 : base (null, new Arguments (arguments.Count))
11737 foreach (Expression e in arguments)
11738 base.arguments.Add (new ElementInitializerArgument (e));
11743 public CollectionElementInitializer (Location loc)
11744 : base (null, null)
11749 public override Expression CreateExpressionTree (ResolveContext ec)
11751 Arguments args = new Arguments (2);
11752 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11754 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11755 foreach (Argument a in arguments) {
11756 if (a.ArgType == Argument.AType.ExtensionType) {
11757 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11760 expr_initializers.Add (a.CreateExpressionTree (ec));
11763 args.Add (new Argument (new ArrayCreation (
11764 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11765 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11768 protected override void CloneTo (CloneContext clonectx, Expression t)
11770 CollectionElementInitializer target = (CollectionElementInitializer) t;
11771 if (arguments != null)
11772 target.arguments = arguments.Clone (clonectx);
11775 protected override Expression DoResolve (ResolveContext ec)
11777 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11779 return base.DoResolve (ec);
11783 class DictionaryElementInitializer : ElementInitializer
11785 readonly Arguments args;
11787 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11788 : base (null, initializer, loc)
11790 this.args = arguments;
11793 public override Expression CreateExpressionTree (ResolveContext ec)
11795 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11799 protected override bool ResolveElement (ResolveContext rc)
11801 var init = rc.CurrentInitializerVariable;
11802 var type = init.Type;
11804 if (type.IsArray) {
11805 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11809 if (type.IsPointer) {
11810 target = init.MakePointerAccess (rc, type, args);
11814 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11815 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11816 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11820 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11826 // A block of object or collection initializers
11828 public class CollectionOrObjectInitializers : ExpressionStatement
11830 IList<Expression> initializers;
11831 bool is_collection_initialization;
11833 public CollectionOrObjectInitializers (Location loc)
11834 : this (new Expression[0], loc)
11838 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11840 this.initializers = initializers;
11844 public IList<Expression> Initializers {
11846 return initializers;
11850 public bool IsEmpty {
11852 return initializers.Count == 0;
11856 public bool IsCollectionInitializer {
11858 return is_collection_initialization;
11862 protected override void CloneTo (CloneContext clonectx, Expression target)
11864 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11866 t.initializers = new List<Expression> (initializers.Count);
11867 foreach (var e in initializers)
11868 t.initializers.Add (e.Clone (clonectx));
11871 public override bool ContainsEmitWithAwait ()
11873 foreach (var e in initializers) {
11874 if (e.ContainsEmitWithAwait ())
11881 public override Expression CreateExpressionTree (ResolveContext ec)
11883 return CreateExpressionTree (ec, false);
11886 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11888 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11889 foreach (Expression e in initializers) {
11890 Expression expr = e.CreateExpressionTree (ec);
11892 expr_initializers.Add (expr);
11896 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11898 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11901 protected override Expression DoResolve (ResolveContext ec)
11903 List<string> element_names = null;
11904 for (int i = 0; i < initializers.Count; ++i) {
11905 Expression initializer = initializers [i];
11906 ElementInitializer element_initializer = initializer as ElementInitializer;
11909 if (element_initializer != null) {
11910 element_names = new List<string> (initializers.Count);
11911 if (!element_initializer.IsDictionaryInitializer)
11912 element_names.Add (element_initializer.Name);
11913 } else if (initializer is CompletingExpression) {
11914 initializer.Resolve (ec);
11915 throw new InternalErrorException ("This line should never be reached");
11917 var t = ec.CurrentInitializerVariable.Type;
11918 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11919 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11920 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11921 "object initializer because type `{1}' does not implement `{2}' interface",
11922 ec.CurrentInitializerVariable.GetSignatureForError (),
11923 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11924 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11927 is_collection_initialization = true;
11930 if (is_collection_initialization != (element_initializer == null)) {
11931 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11932 is_collection_initialization ? "collection initializer" : "object initializer");
11936 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11937 if (element_names.Contains (element_initializer.Name)) {
11938 ec.Report.Error (1912, element_initializer.Location,
11939 "An object initializer includes more than one member `{0}' initialization",
11940 element_initializer.Name);
11942 element_names.Add (element_initializer.Name);
11947 Expression e = initializer.Resolve (ec);
11948 if (e == EmptyExpressionStatement.Instance)
11949 initializers.RemoveAt (i--);
11951 initializers [i] = e;
11954 type = ec.CurrentInitializerVariable.Type;
11955 if (is_collection_initialization) {
11956 if (TypeManager.HasElementType (type)) {
11957 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11958 type.GetSignatureForError ());
11962 eclass = ExprClass.Variable;
11966 public override void Emit (EmitContext ec)
11968 EmitStatement (ec);
11971 public override void EmitStatement (EmitContext ec)
11973 foreach (ExpressionStatement e in initializers) {
11974 // TODO: need location region
11975 ec.Mark (e.Location);
11976 e.EmitStatement (ec);
11980 public override void FlowAnalysis (FlowAnalysisContext fc)
11982 foreach (var initializer in initializers) {
11983 if (initializer != null)
11984 initializer.FlowAnalysis (fc);
11990 // New expression with element/object initializers
11992 public class NewInitialize : New
11995 // This class serves as a proxy for variable initializer target instances.
11996 // A real variable is assigned later when we resolve left side of an
11999 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12001 NewInitialize new_instance;
12003 public InitializerTargetExpression (NewInitialize newInstance)
12005 this.type = newInstance.type;
12006 this.loc = newInstance.loc;
12007 this.eclass = newInstance.eclass;
12008 this.new_instance = newInstance;
12011 public override bool ContainsEmitWithAwait ()
12016 public override Expression CreateExpressionTree (ResolveContext ec)
12018 // Should not be reached
12019 throw new NotSupportedException ("ET");
12022 protected override Expression DoResolve (ResolveContext ec)
12027 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12032 public override void Emit (EmitContext ec)
12034 Expression e = (Expression) new_instance.instance;
12038 public override Expression EmitToField (EmitContext ec)
12040 return (Expression) new_instance.instance;
12043 #region IMemoryLocation Members
12045 public void AddressOf (EmitContext ec, AddressOp mode)
12047 new_instance.instance.AddressOf (ec, mode);
12053 CollectionOrObjectInitializers initializers;
12054 IMemoryLocation instance;
12055 DynamicExpressionStatement dynamic;
12057 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12058 : base (requested_type, arguments, l)
12060 this.initializers = initializers;
12063 public CollectionOrObjectInitializers Initializers {
12065 return initializers;
12069 protected override void CloneTo (CloneContext clonectx, Expression t)
12071 base.CloneTo (clonectx, t);
12073 NewInitialize target = (NewInitialize) t;
12074 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12077 public override bool ContainsEmitWithAwait ()
12079 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12082 public override Expression CreateExpressionTree (ResolveContext ec)
12084 Arguments args = new Arguments (2);
12085 args.Add (new Argument (base.CreateExpressionTree (ec)));
12086 if (!initializers.IsEmpty)
12087 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12089 return CreateExpressionFactoryCall (ec,
12090 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12094 protected override Expression DoResolve (ResolveContext ec)
12096 Expression e = base.DoResolve (ec);
12100 if (type.IsDelegate) {
12101 ec.Report.Error (1958, Initializers.Location,
12102 "Object and collection initializers cannot be used to instantiate a delegate");
12105 Expression previous = ec.CurrentInitializerVariable;
12106 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12107 initializers.Resolve (ec);
12108 ec.CurrentInitializerVariable = previous;
12110 dynamic = e as DynamicExpressionStatement;
12111 if (dynamic != null)
12117 public override void Emit (EmitContext ec)
12119 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12120 var fe = ec.GetTemporaryField (type);
12122 if (!Emit (ec, fe))
12131 public override bool Emit (EmitContext ec, IMemoryLocation target)
12134 // Expression is initialized into temporary target then moved
12135 // to real one for atomicity
12137 IMemoryLocation temp_target = target;
12139 LocalTemporary temp = null;
12140 bool by_ref = false;
12141 if (!initializers.IsEmpty) {
12142 temp_target = target as LocalTemporary;
12143 if (temp_target == null)
12144 temp_target = target as StackFieldExpr;
12146 if (temp_target == null) {
12147 var vr = target as VariableReference;
12148 if (vr != null && vr.IsRef) {
12154 if (temp_target == null)
12155 temp_target = temp = new LocalTemporary (type);
12158 bool left_on_stack;
12159 if (dynamic != null) {
12161 left_on_stack = true;
12163 left_on_stack = base.Emit (ec, temp_target);
12166 if (initializers.IsEmpty)
12167 return left_on_stack;
12169 StackFieldExpr sf = null;
12171 // Move a new instance (reference-type) to local temporary variable
12172 if (left_on_stack) {
12174 temp_target = temp = new LocalTemporary (type);
12180 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12182 throw new NotImplementedException ();
12184 sf = ec.GetTemporaryField (type);
12185 sf.EmitAssign (ec, temp, false, false);
12188 left_on_stack = false;
12192 instance = temp_target;
12194 initializers.Emit (ec);
12196 ((Expression)temp_target).Emit (ec);
12202 sf.IsAvailableForReuse = true;
12207 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12209 instance = base.EmitAddressOf (ec, Mode);
12211 if (!initializers.IsEmpty)
12212 initializers.Emit (ec);
12217 public override void FlowAnalysis (FlowAnalysisContext fc)
12219 base.FlowAnalysis (fc);
12220 initializers.FlowAnalysis (fc);
12223 public override object Accept (StructuralVisitor visitor)
12225 return visitor.Visit (this);
12229 public class NewAnonymousType : New
12231 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12233 List<AnonymousTypeParameter> parameters;
12234 readonly TypeContainer parent;
12235 AnonymousTypeClass anonymous_type;
12237 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12238 : base (null, null, loc)
12240 this.parameters = parameters;
12241 this.parent = parent;
12244 public List<AnonymousTypeParameter> Parameters {
12246 return this.parameters;
12250 protected override void CloneTo (CloneContext clonectx, Expression target)
12252 if (parameters == null)
12255 NewAnonymousType t = (NewAnonymousType) target;
12256 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12257 foreach (AnonymousTypeParameter atp in parameters)
12258 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12261 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12263 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12267 type = AnonymousTypeClass.Create (parent, parameters, loc);
12271 int errors = ec.Report.Errors;
12272 type.CreateContainer ();
12273 type.DefineContainer ();
12275 if ((ec.Report.Errors - errors) == 0) {
12276 parent.Module.AddAnonymousType (type);
12277 type.PrepareEmit ();
12283 public override Expression CreateExpressionTree (ResolveContext ec)
12285 if (parameters == null)
12286 return base.CreateExpressionTree (ec);
12288 var init = new ArrayInitializer (parameters.Count, loc);
12289 foreach (var m in anonymous_type.Members) {
12290 var p = m as Property;
12292 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12295 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12296 foreach (Argument a in arguments)
12297 ctor_args.Add (a.CreateExpressionTree (ec));
12299 Arguments args = new Arguments (3);
12300 args.Add (new Argument (new TypeOfMethod (method, loc)));
12301 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12302 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12304 return CreateExpressionFactoryCall (ec, "New", args);
12307 protected override Expression DoResolve (ResolveContext ec)
12309 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12310 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12314 if (parameters == null) {
12315 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12316 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12317 return base.DoResolve (ec);
12320 bool error = false;
12321 arguments = new Arguments (parameters.Count);
12322 var t_args = new TypeSpec [parameters.Count];
12323 for (int i = 0; i < parameters.Count; ++i) {
12324 Expression e = parameters [i].Resolve (ec);
12330 arguments.Add (new Argument (e));
12331 t_args [i] = e.Type;
12337 anonymous_type = CreateAnonymousType (ec, parameters);
12338 if (anonymous_type == null)
12341 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12342 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12343 eclass = ExprClass.Value;
12347 public override object Accept (StructuralVisitor visitor)
12349 return visitor.Visit (this);
12353 public class AnonymousTypeParameter : ShimExpression
12355 public readonly string Name;
12357 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12358 : base (initializer)
12364 public AnonymousTypeParameter (Parameter parameter)
12365 : base (new SimpleName (parameter.Name, parameter.Location))
12367 this.Name = parameter.Name;
12368 this.loc = parameter.Location;
12371 public override bool Equals (object o)
12373 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12374 return other != null && Name == other.Name;
12377 public override int GetHashCode ()
12379 return Name.GetHashCode ();
12382 protected override Expression DoResolve (ResolveContext ec)
12384 Expression e = expr.Resolve (ec);
12388 if (e.eclass == ExprClass.MethodGroup) {
12389 Error_InvalidInitializer (ec, e.ExprClassName);
12394 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12395 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12402 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12404 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12405 Name, initializer);
12409 public class CatchFilterExpression : BooleanExpression
12411 public CatchFilterExpression (Expression expr, Location loc)
12418 public class InterpolatedString : Expression
12420 readonly StringLiteral start, end;
12421 List<Expression> interpolations;
12422 Arguments arguments;
12424 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12426 this.start = start;
12428 this.interpolations = interpolations;
12429 loc = start.Location;
12432 protected override void CloneTo (CloneContext clonectx, Expression t)
12434 InterpolatedString target = (InterpolatedString) t;
12436 if (interpolations != null) {
12437 target.interpolations = new List<Expression> ();
12438 foreach (var interpolation in interpolations) {
12439 target.interpolations.Add (interpolation.Clone (clonectx));
12444 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12446 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12447 if (factory == null)
12450 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12451 var res = new Invocation (ma, arguments).Resolve (rc);
12452 if (res != null && res.Type != type)
12453 res = Convert.ExplicitConversion (rc, res, type, loc);
12458 public override bool ContainsEmitWithAwait ()
12460 if (interpolations == null)
12463 foreach (var expr in interpolations) {
12464 if (expr.ContainsEmitWithAwait ())
12471 public override Expression CreateExpressionTree (ResolveContext rc)
12473 var best = ResolveBestFormatOverload (rc);
12477 Expression instance = new NullLiteral (loc);
12478 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12479 return CreateExpressionFactoryCall (rc, "Call", args);
12482 protected override Expression DoResolve (ResolveContext rc)
12486 if (interpolations == null) {
12488 arguments = new Arguments (1);
12490 for (int i = 0; i < interpolations.Count; i += 2) {
12491 var ipi = (InterpolatedStringInsert)interpolations [i];
12495 arguments = new Arguments (interpolations.Count);
12497 var sb = new StringBuilder (start.Value);
12498 for (int i = 0; i < interpolations.Count; ++i) {
12500 sb.Append ('{').Append (i / 2);
12501 var isi = (InterpolatedStringInsert)interpolations [i];
12502 if (isi.Alignment != null) {
12504 var value = isi.ResolveAligment (rc);
12506 sb.Append (value.Value);
12509 if (isi.Format != null) {
12511 sb.Append (isi.Format);
12515 arguments.Add (new Argument (interpolations [i]));
12517 sb.Append (((StringLiteral)interpolations [i]).Value);
12521 sb.Append (end.Value);
12522 str = sb.ToString ();
12525 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12527 eclass = ExprClass.Value;
12528 type = rc.BuiltinTypes.String;
12532 public override void Emit (EmitContext ec)
12534 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12535 if (interpolations == null) {
12536 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12537 if (str != start.Value)
12538 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12545 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12549 var ca = new CallEmitter ();
12550 ca.Emit (ec, best, arguments, loc);
12553 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12555 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12556 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12557 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12561 public class InterpolatedStringInsert : CompositeExpression
12563 public InterpolatedStringInsert (Expression expr)
12568 public Expression Alignment { get; set; }
12569 public string Format { get; set; }
12571 protected override void CloneTo (CloneContext clonectx, Expression t)
12573 var target = (InterpolatedStringInsert)t;
12574 target.expr = expr.Clone (clonectx);
12575 if (Alignment != null)
12576 target.Alignment = Alignment.Clone (clonectx);
12579 protected override Expression DoResolve (ResolveContext rc)
12581 var expr = base.DoResolve (rc);
12586 // For better error reporting, assumes the built-in implementation uses object
12589 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12592 public int? ResolveAligment (ResolveContext rc)
12594 var c = Alignment.ResolveLabelConstant (rc);
12598 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12602 var value = (int) c.GetValueAsLong ();
12603 if (value > 32767 || value < -32767) {
12604 rc.Report.Warning (8094, 1, Alignment.Location,
12605 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");