2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
722 UnsafeError (ec, loc);
724 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
725 if (Expr == null || Expr.eclass != ExprClass.Variable) {
726 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
730 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
734 IVariableReference vr = Expr as IVariableReference;
737 is_fixed = vr.IsFixed;
738 vr.SetHasAddressTaken ();
741 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
744 IFixedExpression fe = Expr as IFixedExpression;
745 is_fixed = fe != null && fe.IsFixed;
748 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
749 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
752 type = PointerContainer.MakeType (ec.Module, Expr.Type);
753 eclass = ExprClass.Value;
757 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
759 expr = DoNumericPromotion (rc, Oper, expr);
760 TypeSpec expr_type = expr.Type;
761 foreach (TypeSpec t in predefined) {
769 // Perform user-operator overload resolution
771 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
773 CSharp.Operator.OpType op_type;
775 case Operator.LogicalNot:
776 op_type = CSharp.Operator.OpType.LogicalNot; break;
777 case Operator.OnesComplement:
778 op_type = CSharp.Operator.OpType.OnesComplement; break;
779 case Operator.UnaryNegation:
780 op_type = CSharp.Operator.OpType.UnaryNegation; break;
781 case Operator.UnaryPlus:
782 op_type = CSharp.Operator.OpType.UnaryPlus; break;
784 throw new InternalErrorException (Oper.ToString ());
787 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
791 Arguments args = new Arguments (1);
792 args.Add (new Argument (expr));
794 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
795 var oper = res.ResolveOperator (ec, ref args);
800 Expr = args [0].Expr;
801 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
805 // Unary user type overload resolution
807 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
809 Expression best_expr = ResolveUserOperator (ec, expr);
810 if (best_expr != null)
813 foreach (TypeSpec t in predefined) {
814 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
815 if (oper_expr == null)
818 if (oper_expr == ErrorExpression.Instance)
822 // decimal type is predefined but has user-operators
824 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
825 oper_expr = ResolveUserType (ec, oper_expr, predefined);
827 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
829 if (oper_expr == null)
832 if (best_expr == null) {
833 best_expr = oper_expr;
837 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
839 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
840 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
842 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
849 best_expr = oper_expr;
852 if (best_expr == null)
856 // HACK: Decimal user-operator is included in standard operators
858 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
862 type = best_expr.Type;
866 protected override void CloneTo (CloneContext clonectx, Expression t)
868 Unary target = (Unary) t;
870 target.Expr = Expr.Clone (clonectx);
873 public override object Accept (StructuralVisitor visitor)
875 return visitor.Visit (this);
881 // Unary operators are turned into Indirection expressions
882 // after semantic analysis (this is so we can take the address
883 // of an indirection).
885 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
887 LocalTemporary temporary;
890 public Indirection (Expression expr, Location l)
896 public Expression Expr {
902 public bool IsFixed {
906 public override Location StartLocation {
908 return expr.StartLocation;
912 protected override void CloneTo (CloneContext clonectx, Expression t)
914 Indirection target = (Indirection) t;
915 target.expr = expr.Clone (clonectx);
918 public override bool ContainsEmitWithAwait ()
920 throw new NotImplementedException ();
923 public override Expression CreateExpressionTree (ResolveContext ec)
925 Error_PointerInsideExpressionTree (ec);
929 public override void Emit (EmitContext ec)
934 ec.EmitLoadFromPtr (Type);
937 public void Emit (EmitContext ec, bool leave_copy)
941 ec.Emit (OpCodes.Dup);
942 temporary = new LocalTemporary (expr.Type);
943 temporary.Store (ec);
947 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
949 prepared = isCompound;
954 ec.Emit (OpCodes.Dup);
958 ec.Emit (OpCodes.Dup);
959 temporary = new LocalTemporary (source.Type);
960 temporary.Store (ec);
963 ec.EmitStoreFromPtr (type);
965 if (temporary != null) {
967 temporary.Release (ec);
971 public void AddressOf (EmitContext ec, AddressOp Mode)
976 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
978 return DoResolve (ec);
981 protected override Expression DoResolve (ResolveContext ec)
983 expr = expr.Resolve (ec);
988 UnsafeError (ec, loc);
990 var pc = expr.Type as PointerContainer;
993 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
999 if (type.Kind == MemberKind.Void) {
1000 Error_VoidPointerOperation (ec);
1004 eclass = ExprClass.Variable;
1008 public override object Accept (StructuralVisitor visitor)
1010 return visitor.Visit (this);
1015 /// Unary Mutator expressions (pre and post ++ and --)
1019 /// UnaryMutator implements ++ and -- expressions. It derives from
1020 /// ExpressionStatement becuase the pre/post increment/decrement
1021 /// operators can be used in a statement context.
1023 /// FIXME: Idea, we could split this up in two classes, one simpler
1024 /// for the common case, and one with the extra fields for more complex
1025 /// classes (indexers require temporary access; overloaded require method)
1028 public class UnaryMutator : ExpressionStatement
1030 class DynamicPostMutator : Expression, IAssignMethod
1032 LocalTemporary temp;
1035 public DynamicPostMutator (Expression expr)
1038 this.type = expr.Type;
1039 this.loc = expr.Location;
1042 public override Expression CreateExpressionTree (ResolveContext ec)
1044 throw new NotImplementedException ("ET");
1047 protected override Expression DoResolve (ResolveContext rc)
1049 eclass = expr.eclass;
1053 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1055 expr.DoResolveLValue (ec, right_side);
1056 return DoResolve (ec);
1059 public override void Emit (EmitContext ec)
1064 public void Emit (EmitContext ec, bool leave_copy)
1066 throw new NotImplementedException ();
1070 // Emits target assignment using unmodified source value
1072 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1075 // Allocate temporary variable to keep original value before it's modified
1077 temp = new LocalTemporary (type);
1081 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1092 public enum Mode : byte {
1099 PreDecrement = IsDecrement,
1100 PostIncrement = IsPost,
1101 PostDecrement = IsPost | IsDecrement
1105 bool is_expr, recurse;
1107 protected Expression expr;
1109 // Holds the real operation
1110 Expression operation;
1112 public UnaryMutator (Mode m, Expression e, Location loc)
1119 public Mode UnaryMutatorMode {
1125 public Expression Expr {
1131 public override Location StartLocation {
1133 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1137 public override bool ContainsEmitWithAwait ()
1139 return expr.ContainsEmitWithAwait ();
1142 public override Expression CreateExpressionTree (ResolveContext ec)
1144 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1147 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1150 // Predefined ++ and -- operators exist for the following types:
1151 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1153 return new TypeSpec[] {
1169 protected override Expression DoResolve (ResolveContext ec)
1171 expr = expr.Resolve (ec);
1173 if (expr == null || expr.Type == InternalType.ErrorType)
1176 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1178 // Handle postfix unary operators using local
1179 // temporary variable
1181 if ((mode & Mode.IsPost) != 0)
1182 expr = new DynamicPostMutator (expr);
1184 Arguments args = new Arguments (1);
1185 args.Add (new Argument (expr));
1186 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1189 if (expr.Type.IsNullableType)
1190 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1192 return DoResolveOperation (ec);
1195 protected Expression DoResolveOperation (ResolveContext ec)
1197 eclass = ExprClass.Value;
1200 if (expr is RuntimeValueExpression) {
1203 // Use itself at the top of the stack
1204 operation = new EmptyExpression (type);
1208 // The operand of the prefix/postfix increment decrement operators
1209 // should be an expression that is classified as a variable,
1210 // a property access or an indexer access
1212 // TODO: Move to parser, expr is ATypeNameExpression
1213 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1214 expr = expr.ResolveLValue (ec, expr);
1216 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1220 // Step 1: Try to find a user operator, it has priority over predefined ones
1222 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1223 var methods = MemberCache.GetUserOperator (type, user_op, false);
1225 if (methods != null) {
1226 Arguments args = new Arguments (1);
1227 args.Add (new Argument (expr));
1229 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1230 var method = res.ResolveOperator (ec, ref args);
1234 args[0].Expr = operation;
1235 operation = new UserOperatorCall (method, args, null, loc);
1236 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1241 // Step 2: Try predefined types
1244 Expression source = null;
1245 bool primitive_type;
1248 // Predefined without user conversion first for speed-up
1250 // Predefined ++ and -- operators exist for the following types:
1251 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1253 switch (type.BuiltinType) {
1254 case BuiltinTypeSpec.Type.Byte:
1255 case BuiltinTypeSpec.Type.SByte:
1256 case BuiltinTypeSpec.Type.Short:
1257 case BuiltinTypeSpec.Type.UShort:
1258 case BuiltinTypeSpec.Type.Int:
1259 case BuiltinTypeSpec.Type.UInt:
1260 case BuiltinTypeSpec.Type.Long:
1261 case BuiltinTypeSpec.Type.ULong:
1262 case BuiltinTypeSpec.Type.Char:
1263 case BuiltinTypeSpec.Type.Float:
1264 case BuiltinTypeSpec.Type.Double:
1265 case BuiltinTypeSpec.Type.Decimal:
1267 primitive_type = true;
1270 primitive_type = false;
1272 // ++/-- on pointer variables of all types except void*
1273 if (type.IsPointer) {
1274 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1275 Error_VoidPointerOperation (ec);
1281 Expression best_source = null;
1282 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1283 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1285 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1289 if (best_source == null) {
1290 best_source = source;
1294 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1299 best_source = source;
1303 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1307 source = best_source;
1310 // ++/-- on enum types
1311 if (source == null && type.IsEnum)
1314 if (source == null) {
1315 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1322 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1323 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1324 operation = new Binary (op, source, one);
1325 operation = operation.Resolve (ec);
1326 if (operation == null)
1327 throw new NotImplementedException ("should not be reached");
1329 if (operation.Type != type) {
1331 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1333 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1339 void EmitCode (EmitContext ec, bool is_expr)
1342 this.is_expr = is_expr;
1343 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1346 public override void Emit (EmitContext ec)
1349 // We use recurse to allow ourselfs to be the source
1350 // of an assignment. This little hack prevents us from
1351 // having to allocate another expression
1354 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1362 EmitCode (ec, true);
1365 protected virtual void EmitOperation (EmitContext ec)
1367 operation.Emit (ec);
1370 public override void EmitStatement (EmitContext ec)
1372 EmitCode (ec, false);
1375 public override void FlowAnalysis (FlowAnalysisContext fc)
1377 expr.FlowAnalysis (fc);
1381 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1383 string GetOperatorExpressionTypeName ()
1385 return IsDecrement ? "Decrement" : "Increment";
1389 get { return (mode & Mode.IsDecrement) != 0; }
1393 public override SLE.Expression MakeExpression (BuilderContext ctx)
1395 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1396 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1397 return SLE.Expression.Assign (target, source);
1400 public static string OperName (Mode oper)
1402 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1405 protected override void CloneTo (CloneContext clonectx, Expression t)
1407 UnaryMutator target = (UnaryMutator) t;
1409 target.expr = expr.Clone (clonectx);
1412 public override object Accept (StructuralVisitor visitor)
1414 return visitor.Visit (this);
1420 // Base class for the `is' and `as' operators
1422 public abstract class Probe : Expression
1424 public Expression ProbeType;
1425 protected Expression expr;
1426 protected TypeSpec probe_type_expr;
1428 protected Probe (Expression expr, Expression probe_type, Location l)
1430 ProbeType = probe_type;
1435 public Expression Expr {
1441 public override bool ContainsEmitWithAwait ()
1443 return expr.ContainsEmitWithAwait ();
1446 protected Expression ResolveCommon (ResolveContext rc)
1448 expr = expr.Resolve (rc);
1452 ResolveProbeType (rc);
1453 if (probe_type_expr == null)
1456 if (probe_type_expr.IsStatic) {
1457 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1458 probe_type_expr.GetSignatureForError ());
1462 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1463 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1468 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1469 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1477 protected virtual void ResolveProbeType (ResolveContext rc)
1479 probe_type_expr = ProbeType.ResolveAsType (rc);
1482 public override void EmitSideEffect (EmitContext ec)
1484 expr.EmitSideEffect (ec);
1487 public override void FlowAnalysis (FlowAnalysisContext fc)
1489 expr.FlowAnalysis (fc);
1492 public override bool HasConditionalAccess ()
1494 return expr.HasConditionalAccess ();
1497 protected abstract string OperatorName { get; }
1499 protected override void CloneTo (CloneContext clonectx, Expression t)
1501 Probe target = (Probe) t;
1503 target.expr = expr.Clone (clonectx);
1504 target.ProbeType = ProbeType.Clone (clonectx);
1510 /// Implementation of the `is' operator.
1512 public class Is : Probe
1514 Nullable.Unwrap expr_unwrap;
1515 MethodSpec number_mg;
1516 Arguments number_args;
1518 public Is (Expression expr, Expression probe_type, Location l)
1519 : base (expr, probe_type, l)
1523 protected override string OperatorName {
1524 get { return "is"; }
1527 public LocalVariable Variable { get; set; }
1529 public override Expression CreateExpressionTree (ResolveContext ec)
1531 if (Variable != null)
1532 throw new NotSupportedException ();
1534 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1535 expr.CreateExpressionTree (ec),
1536 new TypeOf (probe_type_expr, loc));
1538 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1541 Expression CreateConstantResult (ResolveContext rc, bool result)
1544 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1545 probe_type_expr.GetSignatureForError ());
1547 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1548 probe_type_expr.GetSignatureForError ());
1550 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1551 return expr.IsSideEffectFree ?
1552 ReducedExpression.Create (c, this) :
1553 new SideEffectConstant (c, this, loc);
1556 public override void Emit (EmitContext ec)
1558 if (probe_type_expr == null) {
1559 if (ProbeType is WildcardPattern) {
1560 expr.EmitSideEffect (ec);
1561 ProbeType.Emit (ec);
1563 EmitPatternMatch (ec);
1570 if (expr_unwrap == null) {
1572 ec.Emit (OpCodes.Cgt_Un);
1576 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1578 if (probe_type_expr == null) {
1579 EmitPatternMatch (ec);
1584 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1587 void EmitPatternMatch (EmitContext ec)
1589 var no_match = ec.DefineLabel ();
1590 var end = ec.DefineLabel ();
1592 if (expr_unwrap != null) {
1593 expr_unwrap.EmitCheck (ec);
1595 if (ProbeType.IsNull) {
1597 ec.Emit (OpCodes.Ceq);
1601 ec.Emit (OpCodes.Brfalse_S, no_match);
1602 expr_unwrap.Emit (ec);
1603 ProbeType.Emit (ec);
1604 ec.Emit (OpCodes.Ceq);
1605 ec.Emit (OpCodes.Br_S, end);
1606 ec.MarkLabel (no_match);
1612 if (number_args != null && number_args.Count == 3) {
1613 var ce = new CallEmitter ();
1614 ce.Emit (ec, number_mg, number_args, loc);
1618 var probe_type = ProbeType.Type;
1621 ec.Emit (OpCodes.Isinst, probe_type);
1622 ec.Emit (OpCodes.Dup);
1623 ec.Emit (OpCodes.Brfalse, no_match);
1625 bool complex_pattern = ProbeType is ComplexPatternExpression;
1626 Label prev = ec.RecursivePatternLabel;
1627 if (complex_pattern)
1628 ec.RecursivePatternLabel = ec.DefineLabel ();
1630 if (number_mg != null) {
1631 var ce = new CallEmitter ();
1632 ce.Emit (ec, number_mg, number_args, loc);
1634 if (TypeSpec.IsValueType (probe_type))
1635 ec.Emit (OpCodes.Unbox_Any, probe_type);
1637 ProbeType.Emit (ec);
1638 if (complex_pattern) {
1641 ec.Emit (OpCodes.Ceq);
1644 ec.Emit (OpCodes.Br_S, end);
1645 ec.MarkLabel (no_match);
1647 ec.Emit (OpCodes.Pop);
1649 if (complex_pattern)
1650 ec.MarkLabel (ec.RecursivePatternLabel);
1652 ec.RecursivePatternLabel = prev;
1658 void EmitLoad (EmitContext ec)
1660 Label no_value_label = new Label ();
1662 if (expr_unwrap != null) {
1663 expr_unwrap.EmitCheck (ec);
1665 if (Variable == null)
1668 ec.Emit (OpCodes.Dup);
1669 no_value_label = ec.DefineLabel ();
1670 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1671 expr_unwrap.Emit (ec);
1675 // Only to make verifier happy
1676 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1677 ec.Emit (OpCodes.Box, expr.Type);
1679 ec.Emit (OpCodes.Isinst, probe_type_expr);
1682 if (Variable != null) {
1683 bool value_on_stack;
1684 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1685 ec.Emit (OpCodes.Dup);
1686 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1687 value_on_stack = true;
1689 value_on_stack = false;
1692 Variable.CreateBuilder (ec);
1693 Variable.EmitAssign (ec);
1695 if (expr_unwrap != null) {
1696 ec.MarkLabel (no_value_label);
1697 } else if (!value_on_stack) {
1703 protected override Expression DoResolve (ResolveContext rc)
1705 if (ResolveCommon (rc) == null)
1708 type = rc.BuiltinTypes.Bool;
1709 eclass = ExprClass.Value;
1711 if (probe_type_expr == null)
1712 return ResolveMatchingExpression (rc);
1714 var res = ResolveResultExpression (rc);
1715 if (Variable != null) {
1716 if (res is Constant)
1717 throw new NotImplementedException ("constant in type pattern matching");
1719 Variable.Type = probe_type_expr;
1720 var bc = rc as BlockContext;
1722 Variable.PrepareAssignmentAnalysis (bc);
1728 public override void FlowAnalysis (FlowAnalysisContext fc)
1730 base.FlowAnalysis (fc);
1732 if (Variable != null)
1733 fc.SetVariableAssigned (Variable.VariableInfo, true);
1736 protected override void ResolveProbeType (ResolveContext rc)
1738 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1739 if (ProbeType is PatternExpression) {
1740 ProbeType.Resolve (rc);
1745 // Have to use session recording because we don't have reliable type probing
1746 // mechanism (similar issue as in attributes resolving)
1748 // TODO: This is still wrong because ResolveAsType can be destructive
1750 var type_printer = new SessionReportPrinter ();
1751 var prev_recorder = rc.Report.SetPrinter (type_printer);
1753 probe_type_expr = ProbeType.ResolveAsType (rc);
1754 type_printer.EndSession ();
1756 if (probe_type_expr != null) {
1757 type_printer.Merge (rc.Report.Printer);
1758 rc.Report.SetPrinter (prev_recorder);
1762 var vexpr = ProbeType as VarExpr;
1763 if (vexpr != null && vexpr.InferType (rc, expr)) {
1764 probe_type_expr = vexpr.Type;
1765 rc.Report.SetPrinter (prev_recorder);
1769 var expr_printer = new SessionReportPrinter ();
1770 rc.Report.SetPrinter (expr_printer);
1771 ProbeType = ProbeType.Resolve (rc);
1772 expr_printer.EndSession ();
1774 if (ProbeType != null) {
1775 expr_printer.Merge (rc.Report.Printer);
1777 type_printer.Merge (rc.Report.Printer);
1780 rc.Report.SetPrinter (prev_recorder);
1784 base.ResolveProbeType (rc);
1787 Expression ResolveMatchingExpression (ResolveContext rc)
1789 var mc = ProbeType as Constant;
1791 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1792 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1797 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1799 var c = Expr as Constant;
1801 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1806 if (Expr.Type.IsNullableType) {
1807 expr_unwrap = new Nullable.Unwrap (Expr);
1808 expr_unwrap.Resolve (rc);
1809 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1810 } else if (ProbeType.Type == Expr.Type) {
1811 // TODO: Better error handling
1812 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1813 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1814 var helper = rc.Module.CreatePatterMatchingHelper ();
1815 number_mg = helper.NumberMatcher.Spec;
1818 // There are actually 3 arguments but the first one is already on the stack
1820 number_args = new Arguments (3);
1821 if (!ProbeType.Type.IsEnum)
1822 number_args.Add (new Argument (Expr));
1824 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1825 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1831 if (ProbeType is PatternExpression) {
1832 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1833 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1839 // TODO: Better error message
1840 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1844 Expression ResolveResultExpression (ResolveContext ec)
1846 TypeSpec d = expr.Type;
1847 bool d_is_nullable = false;
1850 // If E is a method group or the null literal, or if the type of E is a reference
1851 // type or a nullable type and the value of E is null, the result is false
1853 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1854 return CreateConstantResult (ec, false);
1856 if (d.IsNullableType) {
1857 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1858 if (!ut.IsGenericParameter) {
1860 d_is_nullable = true;
1864 TypeSpec t = probe_type_expr;
1865 bool t_is_nullable = false;
1866 if (t.IsNullableType) {
1867 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1868 if (!ut.IsGenericParameter) {
1870 t_is_nullable = true;
1877 // D and T are the same value types but D can be null
1879 if (d_is_nullable && !t_is_nullable) {
1880 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1885 // The result is true if D and T are the same value types
1887 return CreateConstantResult (ec, true);
1890 var tp = d as TypeParameterSpec;
1892 return ResolveGenericParameter (ec, t, tp);
1895 // An unboxing conversion exists
1897 if (Convert.ExplicitReferenceConversionExists (d, t))
1901 // open generic type
1903 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1906 var tps = t as TypeParameterSpec;
1908 return ResolveGenericParameter (ec, d, tps);
1910 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1911 ec.Report.Warning (1981, 3, loc,
1912 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1913 OperatorName, t.GetSignatureForError ());
1916 if (TypeManager.IsGenericParameter (d))
1917 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1919 if (TypeSpec.IsValueType (d)) {
1920 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1921 if (d_is_nullable && !t_is_nullable) {
1922 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1926 return CreateConstantResult (ec, true);
1929 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1930 var c = expr as Constant;
1932 return CreateConstantResult (ec, !c.IsNull);
1935 // Do not optimize for imported type or dynamic type
1937 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1938 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1942 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1946 // Turn is check into simple null check for implicitly convertible reference types
1948 return ReducedExpression.Create (
1949 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1953 if (Convert.ExplicitReferenceConversionExists (d, t))
1957 // open generic type
1959 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1964 return CreateConstantResult (ec, false);
1967 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1969 if (t.IsReferenceType) {
1971 return CreateConstantResult (ec, false);
1974 if (expr.Type.IsGenericParameter) {
1975 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1976 return CreateConstantResult (ec, true);
1978 expr = new BoxedCast (expr, d);
1984 public override object Accept (StructuralVisitor visitor)
1986 return visitor.Visit (this);
1990 class WildcardPattern : PatternExpression
1992 public WildcardPattern (Location loc)
1997 protected override Expression DoResolve (ResolveContext rc)
1999 eclass = ExprClass.Value;
2000 type = rc.BuiltinTypes.Object;
2004 public override void Emit (EmitContext ec)
2010 class RecursivePattern : ComplexPatternExpression
2012 MethodGroupExpr operator_mg;
2013 Arguments operator_args;
2015 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2016 : base (typeExpresion, loc)
2018 Arguments = arguments;
2021 public Arguments Arguments { get; private set; }
2023 protected override Expression DoResolve (ResolveContext rc)
2025 type = TypeExpression.ResolveAsType (rc);
2029 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2030 if (operators == null) {
2031 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2035 var ops = FindMatchingOverloads (operators);
2037 // TODO: better error message
2038 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2043 Arguments.Resolve (rc, out dynamic_args);
2045 throw new NotImplementedException ("dynamic argument");
2047 var op = FindBestOverload (rc, ops);
2049 // TODO: better error message
2050 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2054 var op_types = op.Parameters.Types;
2055 operator_args = new Arguments (op_types.Length);
2056 operator_args.Add (new Argument (new EmptyExpression (type)));
2058 for (int i = 0; i < Arguments.Count; ++i) {
2059 // TODO: Needs releasing optimization
2060 var lt = new LocalTemporary (op_types [i + 1]);
2061 operator_args.Add (new Argument (lt, Argument.AType.Out));
2063 if (comparisons == null)
2064 comparisons = new Expression[Arguments.Count];
2069 var arg = Arguments [i];
2070 var named = arg as NamedArgument;
2071 if (named != null) {
2072 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2073 expr = Arguments [arg_comp_index].Expr;
2079 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2082 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2084 eclass = ExprClass.Value;
2088 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2090 int arg_count = Arguments.Count + 1;
2091 List<MethodSpec> best = null;
2092 foreach (MethodSpec method in members) {
2093 var pm = method.Parameters;
2094 if (pm.Count != arg_count)
2097 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2099 for (int ii = 1; ii < pm.Count; ++ii) {
2100 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2110 best = new List<MethodSpec> ();
2118 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2120 for (int ii = 0; ii < Arguments.Count; ++ii) {
2121 var arg = Arguments [ii];
2122 var expr = arg.Expr;
2123 if (expr is WildcardPattern)
2126 var na = arg as NamedArgument;
2127 for (int i = 0; i < methods.Count; ++i) {
2128 var pd = methods [i].Parameters;
2132 index = pd.GetParameterIndexByName (na.Name);
2134 methods.RemoveAt (i--);
2141 var m = pd.Types [index];
2142 if (!Convert.ImplicitConversionExists (rc, expr, m))
2143 methods.RemoveAt (i--);
2147 if (methods.Count != 1)
2153 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2155 operator_mg.EmitCall (ec, operator_args, false);
2156 ec.Emit (OpCodes.Brfalse, target);
2158 base.EmitBranchable (ec, target, on_true);
2161 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2163 if (expr is WildcardPattern)
2164 return new EmptyExpression (expr.Type);
2166 var recursive = expr as RecursivePattern;
2167 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2171 if (recursive != null) {
2172 recursive.SetParentInstance (lt);
2176 // TODO: Better error handling
2177 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2180 public void SetParentInstance (Expression instance)
2182 operator_args [0] = new Argument (instance);
2186 class PropertyPattern : ComplexPatternExpression
2188 LocalTemporary instance;
2190 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2191 : base (typeExpresion, loc)
2196 public List<PropertyPatternMember> Members { get; private set; }
2198 protected override Expression DoResolve (ResolveContext rc)
2200 type = TypeExpression.ResolveAsType (rc);
2204 comparisons = new Expression[Members.Count];
2206 // TODO: optimize when source is VariableReference, it'd save dup+pop
2207 instance = new LocalTemporary (type);
2209 for (int i = 0; i < Members.Count; i++) {
2210 var lookup = Members [i];
2212 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2213 if (member == null) {
2214 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2215 if (member != null) {
2216 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2221 if (member == null) {
2222 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2226 var pe = member as PropertyExpr;
2227 if (pe == null || member is FieldExpr) {
2228 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2232 // TODO: Obsolete checks
2233 // TODO: check accessibility
2234 if (pe != null && !pe.PropertyInfo.HasGet) {
2235 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2239 var expr = lookup.Expr.Resolve (rc);
2243 var me = (MemberExpr)member;
2244 me.InstanceExpression = instance;
2246 comparisons [i] = ResolveComparison (rc, expr, me);
2249 eclass = ExprClass.Value;
2253 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2255 if (expr is WildcardPattern)
2256 return new EmptyExpression (expr.Type);
2258 return new Is (instance, expr, expr.Location).Resolve (rc);
2261 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2263 instance.Store (ec);
2265 base.EmitBranchable (ec, target, on_true);
2269 class PropertyPatternMember
2271 public PropertyPatternMember (string name, Expression expr, Location loc)
2278 public string Name { get; private set; }
2279 public Expression Expr { get; private set; }
2280 public Location Location { get; private set; }
2283 abstract class PatternExpression : Expression
2285 protected PatternExpression (Location loc)
2290 public override Expression CreateExpressionTree (ResolveContext ec)
2292 throw new NotImplementedException ();
2296 abstract class ComplexPatternExpression : PatternExpression
2298 protected Expression[] comparisons;
2300 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2303 TypeExpression = typeExpresion;
2306 public ATypeNameExpression TypeExpression { get; private set; }
2308 public override void Emit (EmitContext ec)
2310 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2313 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2315 if (comparisons != null) {
2316 foreach (var comp in comparisons) {
2317 comp.EmitBranchable (ec, target, false);
2324 /// Implementation of the `as' operator.
2326 public class As : Probe {
2328 public As (Expression expr, Expression probe_type, Location l)
2329 : base (expr, probe_type, l)
2333 protected override string OperatorName {
2334 get { return "as"; }
2337 public override Expression CreateExpressionTree (ResolveContext ec)
2339 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2340 expr.CreateExpressionTree (ec),
2341 new TypeOf (probe_type_expr, loc));
2343 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2346 public override void Emit (EmitContext ec)
2350 ec.Emit (OpCodes.Isinst, type);
2352 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2353 ec.Emit (OpCodes.Unbox_Any, type);
2356 protected override Expression DoResolve (ResolveContext ec)
2358 if (ResolveCommon (ec) == null)
2361 type = probe_type_expr;
2362 eclass = ExprClass.Value;
2363 TypeSpec etype = expr.Type;
2365 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2366 if (TypeManager.IsGenericParameter (type)) {
2367 ec.Report.Error (413, loc,
2368 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2369 probe_type_expr.GetSignatureForError ());
2371 ec.Report.Error (77, loc,
2372 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2373 type.GetSignatureForError ());
2378 if (expr.IsNull && type.IsNullableType) {
2379 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2382 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2383 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2387 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2389 e = EmptyCast.Create (e, type);
2390 return ReducedExpression.Create (e, this).Resolve (ec);
2393 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2394 if (TypeManager.IsGenericParameter (etype))
2395 expr = new BoxedCast (expr, etype);
2400 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2401 expr = new BoxedCast (expr, etype);
2405 if (etype != InternalType.ErrorType) {
2406 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2407 etype.GetSignatureForError (), type.GetSignatureForError ());
2413 public override object Accept (StructuralVisitor visitor)
2415 return visitor.Visit (this);
2420 // This represents a typecast in the source language.
2422 public class Cast : ShimExpression {
2423 Expression target_type;
2425 public Cast (Expression cast_type, Expression expr, Location loc)
2428 this.target_type = cast_type;
2432 public Expression TargetType {
2433 get { return target_type; }
2436 protected override Expression DoResolve (ResolveContext ec)
2438 expr = expr.Resolve (ec);
2442 type = target_type.ResolveAsType (ec);
2446 if (type.IsStatic) {
2447 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2451 if (type.IsPointer && !ec.IsUnsafe) {
2452 UnsafeError (ec, loc);
2455 eclass = ExprClass.Value;
2457 Constant c = expr as Constant;
2459 c = c.Reduce (ec, type);
2464 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2466 return EmptyCast.Create (res, type);
2471 protected override void CloneTo (CloneContext clonectx, Expression t)
2473 Cast target = (Cast) t;
2475 target.target_type = target_type.Clone (clonectx);
2476 target.expr = expr.Clone (clonectx);
2479 public override object Accept (StructuralVisitor visitor)
2481 return visitor.Visit (this);
2485 public class ImplicitCast : ShimExpression
2489 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2492 this.loc = expr.Location;
2494 this.arrayAccess = arrayAccess;
2497 protected override Expression DoResolve (ResolveContext ec)
2499 expr = expr.Resolve (ec);
2504 expr = ConvertExpressionToArrayIndex (ec, expr);
2506 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2512 public class DeclarationExpression : Expression, IMemoryLocation
2514 LocalVariableReference lvr;
2516 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2518 VariableType = variableType;
2519 Variable = variable;
2520 this.loc = variable.Location;
2523 public LocalVariable Variable { get; set; }
2524 public Expression Initializer { get; set; }
2525 public FullNamedExpression VariableType { get; set; }
2527 public void AddressOf (EmitContext ec, AddressOp mode)
2529 Variable.CreateBuilder (ec);
2531 if (Initializer != null) {
2532 lvr.EmitAssign (ec, Initializer, false, false);
2535 lvr.AddressOf (ec, mode);
2538 protected override void CloneTo (CloneContext clonectx, Expression t)
2540 var target = (DeclarationExpression) t;
2542 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2544 if (Initializer != null)
2545 target.Initializer = Initializer.Clone (clonectx);
2548 public override Expression CreateExpressionTree (ResolveContext rc)
2550 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2554 bool DoResolveCommon (ResolveContext rc)
2556 var var_expr = VariableType as VarExpr;
2557 if (var_expr != null) {
2558 type = InternalType.VarOutType;
2560 type = VariableType.ResolveAsType (rc);
2565 if (Initializer != null) {
2566 Initializer = Initializer.Resolve (rc);
2568 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2569 type = var_expr.Type;
2573 Variable.Type = type;
2574 lvr = new LocalVariableReference (Variable, loc);
2576 eclass = ExprClass.Variable;
2580 protected override Expression DoResolve (ResolveContext rc)
2582 if (DoResolveCommon (rc))
2588 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2590 if (lvr == null && DoResolveCommon (rc))
2591 lvr.ResolveLValue (rc, right_side);
2596 public override void Emit (EmitContext ec)
2598 throw new NotImplementedException ();
2603 // C# 2.0 Default value expression
2605 public class DefaultValueExpression : Expression
2609 public DefaultValueExpression (Expression expr, Location loc)
2615 public Expression Expr {
2621 public override bool IsSideEffectFree {
2627 public override bool ContainsEmitWithAwait ()
2632 public override Expression CreateExpressionTree (ResolveContext ec)
2634 Arguments args = new Arguments (2);
2635 args.Add (new Argument (this));
2636 args.Add (new Argument (new TypeOf (type, loc)));
2637 return CreateExpressionFactoryCall (ec, "Constant", args);
2640 protected override Expression DoResolve (ResolveContext ec)
2642 type = expr.ResolveAsType (ec);
2646 if (type.IsStatic) {
2647 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2651 return new NullLiteral (Location).ConvertImplicitly (type);
2653 if (TypeSpec.IsReferenceType (type))
2654 return new NullConstant (type, loc);
2656 Constant c = New.Constantify (type, expr.Location);
2660 eclass = ExprClass.Variable;
2664 public override void Emit (EmitContext ec)
2666 LocalTemporary temp_storage = new LocalTemporary(type);
2668 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2669 ec.Emit(OpCodes.Initobj, type);
2670 temp_storage.Emit(ec);
2671 temp_storage.Release (ec);
2675 public override SLE.Expression MakeExpression (BuilderContext ctx)
2677 return SLE.Expression.Default (type.GetMetaInfo ());
2681 protected override void CloneTo (CloneContext clonectx, Expression t)
2683 DefaultValueExpression target = (DefaultValueExpression) t;
2685 target.expr = expr.Clone (clonectx);
2688 public override object Accept (StructuralVisitor visitor)
2690 return visitor.Visit (this);
2695 /// Binary operators
2697 public class Binary : Expression, IDynamicBinder
2699 public class PredefinedOperator
2701 protected readonly TypeSpec left;
2702 protected readonly TypeSpec right;
2703 protected readonly TypeSpec left_unwrap;
2704 protected readonly TypeSpec right_unwrap;
2705 public readonly Operator OperatorsMask;
2706 public TypeSpec ReturnType;
2708 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2709 : this (ltype, rtype, op_mask, ltype)
2713 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2714 : this (type, type, op_mask, return_type)
2718 public PredefinedOperator (TypeSpec type, Operator op_mask)
2719 : this (type, type, op_mask, type)
2723 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2725 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2726 throw new InternalErrorException ("Only masked values can be used");
2728 if ((op_mask & Operator.NullableMask) != 0) {
2729 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2730 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2732 left_unwrap = ltype;
2733 right_unwrap = rtype;
2738 this.OperatorsMask = op_mask;
2739 this.ReturnType = return_type;
2742 public bool IsLifted {
2744 return (OperatorsMask & Operator.NullableMask) != 0;
2748 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2752 var left_expr = b.left;
2753 var right_expr = b.right;
2755 b.type = ReturnType;
2758 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2759 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2760 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2763 if (right_expr.IsNull) {
2764 if ((b.oper & Operator.EqualityMask) != 0) {
2765 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2766 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2767 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2768 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2769 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2771 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2772 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2774 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2775 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2777 return b.CreateLiftedValueTypeResult (rc, left);
2779 } else if (left_expr.IsNull) {
2780 if ((b.oper & Operator.EqualityMask) != 0) {
2781 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2782 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2783 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2784 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2785 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2787 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2788 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2790 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2791 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2793 return b.CreateLiftedValueTypeResult (rc, right);
2799 // A user operators does not support multiple user conversions, but decimal type
2800 // is considered to be predefined type therefore we apply predefined operators rules
2801 // and then look for decimal user-operator implementation
2803 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2804 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2805 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2807 return b.ResolveUserOperator (rc, b.left, b.right);
2810 c = right_expr as Constant;
2812 if (c.IsDefaultValue) {
2816 // (expr + 0) to expr
2817 // (expr - 0) to expr
2818 // (bool? | false) to bool?
2820 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2821 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2822 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2823 return ReducedExpression.Create (b.left, b).Resolve (rc);
2827 // Optimizes (value &/&& 0) to 0
2829 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2830 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2831 return ReducedExpression.Create (side_effect, b);
2835 // Optimizes (bool? & true) to bool?
2837 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2838 return ReducedExpression.Create (b.left, b).Resolve (rc);
2842 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2843 return ReducedExpression.Create (b.left, b).Resolve (rc);
2845 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2846 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2850 c = b.left as Constant;
2852 if (c.IsDefaultValue) {
2856 // (0 + expr) to expr
2857 // (false | bool?) to bool?
2859 if (b.oper == Operator.Addition ||
2860 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2861 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2862 return ReducedExpression.Create (b.right, b).Resolve (rc);
2866 // Optimizes (false && expr) to false
2868 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2869 // No rhs side-effects
2870 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2871 return ReducedExpression.Create (c, b);
2875 // Optimizes (0 & value) to 0
2877 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2878 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2879 return ReducedExpression.Create (side_effect, b);
2883 // Optimizes (true & bool?) to bool?
2885 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2886 return ReducedExpression.Create (b.right, b).Resolve (rc);
2890 // Optimizes (true || expr) to true
2892 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2893 // No rhs side-effects
2894 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2895 return ReducedExpression.Create (c, b);
2899 if (b.oper == Operator.Multiply && c.IsOneInteger)
2900 return ReducedExpression.Create (b.right, b).Resolve (rc);
2904 var lifted = new Nullable.LiftedBinaryOperator (b);
2906 TypeSpec ltype, rtype;
2907 if (b.left.Type.IsNullableType) {
2908 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2909 ltype = left_unwrap;
2914 if (b.right.Type.IsNullableType) {
2915 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2916 rtype = right_unwrap;
2921 lifted.Left = b.left.IsNull ?
2922 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2923 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2925 lifted.Right = b.right.IsNull ?
2926 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2927 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2929 return lifted.Resolve (rc);
2932 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2933 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2938 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2941 // We are dealing with primitive types only
2943 return left == ltype && ltype == rtype;
2946 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2949 if (left == lexpr.Type && right == rexpr.Type)
2952 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2953 Convert.ImplicitConversionExists (ec, rexpr, right);
2956 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2958 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2959 return best_operator;
2961 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2965 if (left != null && best_operator.left != null) {
2966 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2970 // When second argument is same as the first one, the result is same
2972 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2973 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2976 if (result == 0 || result > 2)
2979 return result == 1 ? best_operator : this;
2983 sealed class PredefinedStringOperator : PredefinedOperator
2985 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2986 : base (type, type, op_mask, retType)
2990 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2991 : base (ltype, rtype, op_mask, retType)
2995 public override Expression ConvertResult (ResolveContext ec, Binary b)
2998 // Use original expression for nullable arguments
3000 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3002 b.left = unwrap.Original;
3004 unwrap = b.right as Nullable.Unwrap;
3006 b.right = unwrap.Original;
3008 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3009 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3012 // Start a new concat expression using converted expression
3014 return StringConcat.Create (ec, b.left, b.right, b.loc);
3018 sealed class PredefinedEqualityOperator : PredefinedOperator
3020 MethodSpec equal_method, inequal_method;
3022 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3023 : base (arg, arg, Operator.EqualityMask, retType)
3027 public override Expression ConvertResult (ResolveContext ec, Binary b)
3029 b.type = ReturnType;
3031 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3032 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3034 Arguments args = new Arguments (2);
3035 args.Add (new Argument (b.left));
3036 args.Add (new Argument (b.right));
3039 if (b.oper == Operator.Equality) {
3040 if (equal_method == null) {
3041 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3042 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3043 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3044 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3046 throw new NotImplementedException (left.GetSignatureForError ());
3049 method = equal_method;
3051 if (inequal_method == null) {
3052 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3053 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3054 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3055 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3057 throw new NotImplementedException (left.GetSignatureForError ());
3060 method = inequal_method;
3063 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3067 class PredefinedPointerOperator : PredefinedOperator
3069 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3070 : base (ltype, rtype, op_mask)
3074 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3075 : base (ltype, rtype, op_mask, retType)
3079 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3080 : base (type, op_mask, return_type)
3084 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3087 if (!lexpr.Type.IsPointer)
3090 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3094 if (right == null) {
3095 if (!rexpr.Type.IsPointer)
3098 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3105 public override Expression ConvertResult (ResolveContext ec, Binary b)
3108 b.left = EmptyCast.Create (b.left, left);
3109 } else if (right != null) {
3110 b.right = EmptyCast.Create (b.right, right);
3113 TypeSpec r_type = ReturnType;
3114 Expression left_arg, right_arg;
3115 if (r_type == null) {
3118 right_arg = b.right;
3119 r_type = b.left.Type;
3123 r_type = b.right.Type;
3127 right_arg = b.right;
3130 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3135 public enum Operator {
3136 Multiply = 0 | ArithmeticMask,
3137 Division = 1 | ArithmeticMask,
3138 Modulus = 2 | ArithmeticMask,
3139 Addition = 3 | ArithmeticMask | AdditionMask,
3140 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3142 LeftShift = 5 | ShiftMask,
3143 RightShift = 6 | ShiftMask,
3145 LessThan = 7 | ComparisonMask | RelationalMask,
3146 GreaterThan = 8 | ComparisonMask | RelationalMask,
3147 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3148 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3149 Equality = 11 | ComparisonMask | EqualityMask,
3150 Inequality = 12 | ComparisonMask | EqualityMask,
3152 BitwiseAnd = 13 | BitwiseMask,
3153 ExclusiveOr = 14 | BitwiseMask,
3154 BitwiseOr = 15 | BitwiseMask,
3156 LogicalAnd = 16 | LogicalMask,
3157 LogicalOr = 17 | LogicalMask,
3162 ValuesOnlyMask = ArithmeticMask - 1,
3163 ArithmeticMask = 1 << 5,
3165 ComparisonMask = 1 << 7,
3166 EqualityMask = 1 << 8,
3167 BitwiseMask = 1 << 9,
3168 LogicalMask = 1 << 10,
3169 AdditionMask = 1 << 11,
3170 SubtractionMask = 1 << 12,
3171 RelationalMask = 1 << 13,
3173 DecomposedMask = 1 << 19,
3174 NullableMask = 1 << 20
3178 public enum State : byte
3182 UserOperatorsExcluded = 1 << 2
3185 readonly Operator oper;
3186 Expression left, right;
3188 ConvCast.Mode enum_conversion;
3190 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3191 : this (oper, left, right, State.Compound)
3195 public Binary (Operator oper, Expression left, Expression right, State state)
3196 : this (oper, left, right)
3201 public Binary (Operator oper, Expression left, Expression right)
3202 : this (oper, left, right, left.Location)
3206 public Binary (Operator oper, Expression left, Expression right, Location loc)
3216 public bool IsCompound {
3218 return (state & State.Compound) != 0;
3222 public Operator Oper {
3228 public Expression Left {
3234 public Expression Right {
3240 public override Location StartLocation {
3242 return left.StartLocation;
3249 /// Returns a stringified representation of the Operator
3251 string OperName (Operator oper)
3255 case Operator.Multiply:
3258 case Operator.Division:
3261 case Operator.Modulus:
3264 case Operator.Addition:
3267 case Operator.Subtraction:
3270 case Operator.LeftShift:
3273 case Operator.RightShift:
3276 case Operator.LessThan:
3279 case Operator.GreaterThan:
3282 case Operator.LessThanOrEqual:
3285 case Operator.GreaterThanOrEqual:
3288 case Operator.Equality:
3291 case Operator.Inequality:
3294 case Operator.BitwiseAnd:
3297 case Operator.BitwiseOr:
3300 case Operator.ExclusiveOr:
3303 case Operator.LogicalOr:
3306 case Operator.LogicalAnd:
3310 s = oper.ToString ();
3320 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3322 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3325 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3327 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3331 l = left.Type.GetSignatureForError ();
3332 r = right.Type.GetSignatureForError ();
3334 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3338 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3340 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3343 public override void FlowAnalysis (FlowAnalysisContext fc)
3346 // Optimized version when on-true/on-false data are not needed
3348 if ((oper & Operator.LogicalMask) == 0) {
3349 left.FlowAnalysis (fc);
3350 right.FlowAnalysis (fc);
3354 left.FlowAnalysisConditional (fc);
3355 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3356 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3358 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3359 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3360 right.FlowAnalysisConditional (fc);
3362 if (oper == Operator.LogicalOr)
3363 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3365 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3368 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3370 if ((oper & Operator.LogicalMask) == 0) {
3371 base.FlowAnalysisConditional (fc);
3375 left.FlowAnalysisConditional (fc);
3376 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3377 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3379 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3380 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3381 right.FlowAnalysisConditional (fc);
3383 var lc = left as Constant;
3384 if (oper == Operator.LogicalOr) {
3385 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3386 if (lc != null && lc.IsDefaultValue)
3387 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3389 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3391 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3392 if (lc != null && !lc.IsDefaultValue)
3393 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3395 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3400 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3402 string GetOperatorExpressionTypeName ()
3405 case Operator.Addition:
3406 return IsCompound ? "AddAssign" : "Add";
3407 case Operator.BitwiseAnd:
3408 return IsCompound ? "AndAssign" : "And";
3409 case Operator.BitwiseOr:
3410 return IsCompound ? "OrAssign" : "Or";
3411 case Operator.Division:
3412 return IsCompound ? "DivideAssign" : "Divide";
3413 case Operator.ExclusiveOr:
3414 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3415 case Operator.Equality:
3417 case Operator.GreaterThan:
3418 return "GreaterThan";
3419 case Operator.GreaterThanOrEqual:
3420 return "GreaterThanOrEqual";
3421 case Operator.Inequality:
3423 case Operator.LeftShift:
3424 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3425 case Operator.LessThan:
3427 case Operator.LessThanOrEqual:
3428 return "LessThanOrEqual";
3429 case Operator.LogicalAnd:
3431 case Operator.LogicalOr:
3433 case Operator.Modulus:
3434 return IsCompound ? "ModuloAssign" : "Modulo";
3435 case Operator.Multiply:
3436 return IsCompound ? "MultiplyAssign" : "Multiply";
3437 case Operator.RightShift:
3438 return IsCompound ? "RightShiftAssign" : "RightShift";
3439 case Operator.Subtraction:
3440 return IsCompound ? "SubtractAssign" : "Subtract";
3442 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3446 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3449 case Operator.Addition:
3450 return CSharp.Operator.OpType.Addition;
3451 case Operator.BitwiseAnd:
3452 case Operator.LogicalAnd:
3453 return CSharp.Operator.OpType.BitwiseAnd;
3454 case Operator.BitwiseOr:
3455 case Operator.LogicalOr:
3456 return CSharp.Operator.OpType.BitwiseOr;
3457 case Operator.Division:
3458 return CSharp.Operator.OpType.Division;
3459 case Operator.Equality:
3460 return CSharp.Operator.OpType.Equality;
3461 case Operator.ExclusiveOr:
3462 return CSharp.Operator.OpType.ExclusiveOr;
3463 case Operator.GreaterThan:
3464 return CSharp.Operator.OpType.GreaterThan;
3465 case Operator.GreaterThanOrEqual:
3466 return CSharp.Operator.OpType.GreaterThanOrEqual;
3467 case Operator.Inequality:
3468 return CSharp.Operator.OpType.Inequality;
3469 case Operator.LeftShift:
3470 return CSharp.Operator.OpType.LeftShift;
3471 case Operator.LessThan:
3472 return CSharp.Operator.OpType.LessThan;
3473 case Operator.LessThanOrEqual:
3474 return CSharp.Operator.OpType.LessThanOrEqual;
3475 case Operator.Modulus:
3476 return CSharp.Operator.OpType.Modulus;
3477 case Operator.Multiply:
3478 return CSharp.Operator.OpType.Multiply;
3479 case Operator.RightShift:
3480 return CSharp.Operator.OpType.RightShift;
3481 case Operator.Subtraction:
3482 return CSharp.Operator.OpType.Subtraction;
3484 throw new InternalErrorException (op.ToString ());
3488 public override bool ContainsEmitWithAwait ()
3490 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3493 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3498 case Operator.Multiply:
3499 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3500 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3501 opcode = OpCodes.Mul_Ovf;
3502 else if (!IsFloat (l))
3503 opcode = OpCodes.Mul_Ovf_Un;
3505 opcode = OpCodes.Mul;
3507 opcode = OpCodes.Mul;
3511 case Operator.Division:
3513 opcode = OpCodes.Div_Un;
3515 opcode = OpCodes.Div;
3518 case Operator.Modulus:
3520 opcode = OpCodes.Rem_Un;
3522 opcode = OpCodes.Rem;
3525 case Operator.Addition:
3526 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3527 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3528 opcode = OpCodes.Add_Ovf;
3529 else if (!IsFloat (l))
3530 opcode = OpCodes.Add_Ovf_Un;
3532 opcode = OpCodes.Add;
3534 opcode = OpCodes.Add;
3537 case Operator.Subtraction:
3538 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3539 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3540 opcode = OpCodes.Sub_Ovf;
3541 else if (!IsFloat (l))
3542 opcode = OpCodes.Sub_Ovf_Un;
3544 opcode = OpCodes.Sub;
3546 opcode = OpCodes.Sub;
3549 case Operator.RightShift:
3550 if (!(right is IntConstant)) {
3551 ec.EmitInt (GetShiftMask (l));
3552 ec.Emit (OpCodes.And);
3556 opcode = OpCodes.Shr_Un;
3558 opcode = OpCodes.Shr;
3561 case Operator.LeftShift:
3562 if (!(right is IntConstant)) {
3563 ec.EmitInt (GetShiftMask (l));
3564 ec.Emit (OpCodes.And);
3567 opcode = OpCodes.Shl;
3570 case Operator.Equality:
3571 opcode = OpCodes.Ceq;
3574 case Operator.Inequality:
3575 ec.Emit (OpCodes.Ceq);
3578 opcode = OpCodes.Ceq;
3581 case Operator.LessThan:
3583 opcode = OpCodes.Clt_Un;
3585 opcode = OpCodes.Clt;
3588 case Operator.GreaterThan:
3590 opcode = OpCodes.Cgt_Un;
3592 opcode = OpCodes.Cgt;
3595 case Operator.LessThanOrEqual:
3596 if (IsUnsigned (l) || IsFloat (l))
3597 ec.Emit (OpCodes.Cgt_Un);
3599 ec.Emit (OpCodes.Cgt);
3602 opcode = OpCodes.Ceq;
3605 case Operator.GreaterThanOrEqual:
3606 if (IsUnsigned (l) || IsFloat (l))
3607 ec.Emit (OpCodes.Clt_Un);
3609 ec.Emit (OpCodes.Clt);
3613 opcode = OpCodes.Ceq;
3616 case Operator.BitwiseOr:
3617 opcode = OpCodes.Or;
3620 case Operator.BitwiseAnd:
3621 opcode = OpCodes.And;
3624 case Operator.ExclusiveOr:
3625 opcode = OpCodes.Xor;
3629 throw new InternalErrorException (oper.ToString ());
3635 static int GetShiftMask (TypeSpec type)
3637 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3640 static bool IsUnsigned (TypeSpec t)
3642 switch (t.BuiltinType) {
3643 case BuiltinTypeSpec.Type.Char:
3644 case BuiltinTypeSpec.Type.UInt:
3645 case BuiltinTypeSpec.Type.ULong:
3646 case BuiltinTypeSpec.Type.UShort:
3647 case BuiltinTypeSpec.Type.Byte:
3654 static bool IsFloat (TypeSpec t)
3656 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3659 public Expression ResolveOperator (ResolveContext rc)
3661 eclass = ExprClass.Value;
3663 TypeSpec l = left.Type;
3664 TypeSpec r = right.Type;
3666 bool primitives_only = false;
3669 // Handles predefined primitive types
3671 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3672 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3673 if ((oper & Operator.ShiftMask) == 0) {
3674 if (!DoBinaryOperatorPromotion (rc))
3677 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3681 if (l.IsPointer || r.IsPointer)
3682 return ResolveOperatorPointer (rc, l, r);
3685 if ((state & State.UserOperatorsExcluded) == 0) {
3686 expr = ResolveUserOperator (rc, left, right);
3691 bool lenum = l.IsEnum;
3692 bool renum = r.IsEnum;
3693 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3697 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3698 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3703 if ((oper & Operator.BitwiseMask) != 0) {
3704 expr = EmptyCast.Create (expr, type);
3705 enum_conversion = GetEnumResultCast (type);
3707 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3708 expr = OptimizeAndOperation (expr);
3712 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3713 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3716 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3717 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3721 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3724 // We cannot break here there is also Enum + String possible match
3725 // which is not ambiguous with predefined enum operators
3728 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3729 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3733 } else if (l.IsDelegate || r.IsDelegate) {
3737 expr = ResolveOperatorDelegate (rc, l, r);
3739 // TODO: Can this be ambiguous
3747 // Equality operators are more complicated
3749 if ((oper & Operator.EqualityMask) != 0) {
3750 return ResolveEquality (rc, l, r, primitives_only);
3753 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3757 if (primitives_only)
3761 // Lifted operators have lower priority
3763 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3766 static bool IsEnumOrNullableEnum (TypeSpec type)
3768 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3772 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3773 // if 'left' is not an enumeration constant, create one from the type of 'right'
3774 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3777 case Operator.BitwiseOr:
3778 case Operator.BitwiseAnd:
3779 case Operator.ExclusiveOr:
3780 case Operator.Equality:
3781 case Operator.Inequality:
3782 case Operator.LessThan:
3783 case Operator.LessThanOrEqual:
3784 case Operator.GreaterThan:
3785 case Operator.GreaterThanOrEqual:
3786 if (left.Type.IsEnum)
3789 if (left.IsZeroInteger)
3790 return left.Reduce (ec, right.Type);
3794 case Operator.Addition:
3795 case Operator.Subtraction:
3798 case Operator.Multiply:
3799 case Operator.Division:
3800 case Operator.Modulus:
3801 case Operator.LeftShift:
3802 case Operator.RightShift:
3803 if (right.Type.IsEnum || left.Type.IsEnum)
3812 // The `|' operator used on types which were extended is dangerous
3814 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3816 OpcodeCast lcast = left as OpcodeCast;
3817 if (lcast != null) {
3818 if (IsUnsigned (lcast.UnderlyingType))
3822 OpcodeCast rcast = right as OpcodeCast;
3823 if (rcast != null) {
3824 if (IsUnsigned (rcast.UnderlyingType))
3828 if (lcast == null && rcast == null)
3831 // FIXME: consider constants
3833 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3834 ec.Report.Warning (675, 3, loc,
3835 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3836 ltype.GetSignatureForError ());
3839 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3841 return new PredefinedOperator[] {
3843 // Pointer arithmetic:
3845 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3846 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3847 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3848 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3850 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3851 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3852 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3853 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3856 // T* operator + (int y, T* x);
3857 // T* operator + (uint y, T *x);
3858 // T* operator + (long y, T *x);
3859 // T* operator + (ulong y, T *x);
3861 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3862 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3863 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3864 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3867 // long operator - (T* x, T *y)
3869 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3873 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3875 TypeSpec bool_type = types.Bool;
3878 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3879 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3880 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3881 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3882 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3883 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3884 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3886 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3887 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3888 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3889 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3890 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3891 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3892 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3894 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3895 // Remaining string operators are in lifted tables
3897 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3899 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3900 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3901 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3905 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3907 var types = module.Compiler.BuiltinTypes;
3910 // Not strictly lifted but need to be in second group otherwise expressions like
3911 // int + null would resolve to +(object, string) instead of +(int?, int?)
3913 var string_operators = new [] {
3914 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3915 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3918 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3919 if (nullable == null)
3920 return string_operators;
3922 var bool_type = types.Bool;
3924 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3925 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3926 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3927 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3928 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3929 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3930 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3931 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3934 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3935 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3936 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3937 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3938 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3939 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3940 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3942 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3943 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3944 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3945 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3946 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3947 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3948 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3950 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3952 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3953 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3954 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3956 string_operators [0],
3957 string_operators [1]
3961 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3963 TypeSpec bool_type = types.Bool;
3966 new PredefinedEqualityOperator (types.String, bool_type),
3967 new PredefinedEqualityOperator (types.Delegate, bool_type),
3968 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3969 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3970 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3971 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3972 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3973 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3975 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3979 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3981 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3983 if (nullable == null)
3984 return new PredefinedOperator [0];
3986 var types = module.Compiler.BuiltinTypes;
3987 var bool_type = types.Bool;
3988 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3989 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3990 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3991 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3992 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3993 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3994 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3995 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3998 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3999 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4000 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4001 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4002 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4003 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4005 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4010 // 7.2.6.2 Binary numeric promotions
4012 bool DoBinaryOperatorPromotion (ResolveContext rc)
4014 TypeSpec ltype = left.Type;
4015 if (ltype.IsNullableType) {
4016 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4020 // This is numeric promotion code only
4022 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4025 TypeSpec rtype = right.Type;
4026 if (rtype.IsNullableType) {
4027 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4030 var lb = ltype.BuiltinType;
4031 var rb = rtype.BuiltinType;
4035 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4036 type = rc.BuiltinTypes.Decimal;
4037 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4038 type = rc.BuiltinTypes.Double;
4039 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4040 type = rc.BuiltinTypes.Float;
4041 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4042 type = rc.BuiltinTypes.ULong;
4044 if (IsSignedType (lb)) {
4045 expr = ConvertSignedConstant (left, type);
4049 } else if (IsSignedType (rb)) {
4050 expr = ConvertSignedConstant (right, type);
4056 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4057 type = rc.BuiltinTypes.Long;
4058 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4059 type = rc.BuiltinTypes.UInt;
4061 if (IsSignedType (lb)) {
4062 expr = ConvertSignedConstant (left, type);
4064 type = rc.BuiltinTypes.Long;
4065 } else if (IsSignedType (rb)) {
4066 expr = ConvertSignedConstant (right, type);
4068 type = rc.BuiltinTypes.Long;
4071 type = rc.BuiltinTypes.Int;
4074 if (ltype != type) {
4075 expr = PromoteExpression (rc, left, type);
4082 if (rtype != type) {
4083 expr = PromoteExpression (rc, right, type);
4093 static bool IsSignedType (BuiltinTypeSpec.Type type)
4096 case BuiltinTypeSpec.Type.Int:
4097 case BuiltinTypeSpec.Type.Short:
4098 case BuiltinTypeSpec.Type.SByte:
4099 case BuiltinTypeSpec.Type.Long:
4106 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4108 var c = expr as Constant;
4112 return c.ConvertImplicitly (type);
4115 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4117 if (expr.Type.IsNullableType) {
4118 return Convert.ImplicitConversionStandard (rc, expr,
4119 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4122 var c = expr as Constant;
4124 return c.ConvertImplicitly (type);
4126 return Convert.ImplicitNumericConversion (expr, type);
4129 protected override Expression DoResolve (ResolveContext ec)
4134 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4135 left = ((ParenthesizedExpression) left).Expr;
4136 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4140 if (left.eclass == ExprClass.Type) {
4141 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4145 left = left.Resolve (ec);
4150 right = right.Resolve (ec);
4154 Constant lc = left as Constant;
4155 Constant rc = right as Constant;
4157 // The conversion rules are ignored in enum context but why
4158 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4159 lc = EnumLiftUp (ec, lc, rc);
4161 rc = EnumLiftUp (ec, rc, lc);
4164 if (rc != null && lc != null) {
4165 int prev_e = ec.Report.Errors;
4166 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4167 if (e != null || ec.Report.Errors != prev_e)
4171 // Comparison warnings
4172 if ((oper & Operator.ComparisonMask) != 0) {
4173 if (left.Equals (right)) {
4174 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4176 CheckOutOfRangeComparison (ec, lc, right.Type);
4177 CheckOutOfRangeComparison (ec, rc, left.Type);
4180 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4181 return DoResolveDynamic (ec);
4183 return DoResolveCore (ec, left, right);
4186 Expression DoResolveDynamic (ResolveContext rc)
4189 var rt = right.Type;
4190 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4191 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4192 Error_OperatorCannotBeApplied (rc, left, right);
4199 // Special handling for logical boolean operators which require rhs not to be
4200 // evaluated based on lhs value
4202 if ((oper & Operator.LogicalMask) != 0) {
4203 Expression cond_left, cond_right, expr;
4205 args = new Arguments (2);
4207 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4208 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4210 var cond_args = new Arguments (1);
4211 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4214 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4215 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4217 left = temp.CreateReferenceExpression (rc, loc);
4218 if (oper == Operator.LogicalAnd) {
4219 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4222 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4226 args.Add (new Argument (left));
4227 args.Add (new Argument (right));
4228 cond_right = new DynamicExpressionStatement (this, args, loc);
4230 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4232 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4233 rc.Report.Error (7083, left.Location,
4234 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4235 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4239 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4240 args.Add (new Argument (right));
4241 right = new DynamicExpressionStatement (this, args, loc);
4244 // bool && dynamic => (temp = left) ? temp && right : temp;
4245 // bool || dynamic => (temp = left) ? temp : temp || right;
4247 if (oper == Operator.LogicalAnd) {
4249 cond_right = temp.CreateReferenceExpression (rc, loc);
4251 cond_left = temp.CreateReferenceExpression (rc, loc);
4255 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4258 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4261 args = new Arguments (2);
4262 args.Add (new Argument (left));
4263 args.Add (new Argument (right));
4264 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4267 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4269 Expression expr = ResolveOperator (ec);
4271 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4273 if (left == null || right == null)
4274 throw new InternalErrorException ("Invalid conversion");
4276 if (oper == Operator.BitwiseOr)
4277 CheckBitwiseOrOnSignExtended (ec);
4282 public override SLE.Expression MakeExpression (BuilderContext ctx)
4284 return MakeExpression (ctx, left, right);
4287 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4289 var le = left.MakeExpression (ctx);
4290 var re = right.MakeExpression (ctx);
4291 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4294 case Operator.Addition:
4295 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4296 case Operator.BitwiseAnd:
4297 return SLE.Expression.And (le, re);
4298 case Operator.BitwiseOr:
4299 return SLE.Expression.Or (le, re);
4300 case Operator.Division:
4301 return SLE.Expression.Divide (le, re);
4302 case Operator.Equality:
4303 return SLE.Expression.Equal (le, re);
4304 case Operator.ExclusiveOr:
4305 return SLE.Expression.ExclusiveOr (le, re);
4306 case Operator.GreaterThan:
4307 return SLE.Expression.GreaterThan (le, re);
4308 case Operator.GreaterThanOrEqual:
4309 return SLE.Expression.GreaterThanOrEqual (le, re);
4310 case Operator.Inequality:
4311 return SLE.Expression.NotEqual (le, re);
4312 case Operator.LeftShift:
4313 return SLE.Expression.LeftShift (le, re);
4314 case Operator.LessThan:
4315 return SLE.Expression.LessThan (le, re);
4316 case Operator.LessThanOrEqual:
4317 return SLE.Expression.LessThanOrEqual (le, re);
4318 case Operator.LogicalAnd:
4319 return SLE.Expression.AndAlso (le, re);
4320 case Operator.LogicalOr:
4321 return SLE.Expression.OrElse (le, re);
4322 case Operator.Modulus:
4323 return SLE.Expression.Modulo (le, re);
4324 case Operator.Multiply:
4325 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4326 case Operator.RightShift:
4327 return SLE.Expression.RightShift (le, re);
4328 case Operator.Subtraction:
4329 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4331 throw new NotImplementedException (oper.ToString ());
4336 // D operator + (D x, D y)
4337 // D operator - (D x, D y)
4339 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4341 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4343 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4344 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4349 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4350 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4360 MethodSpec method = null;
4361 Arguments args = new Arguments (2);
4362 args.Add (new Argument (left));
4363 args.Add (new Argument (right));
4365 if (oper == Operator.Addition) {
4366 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4367 } else if (oper == Operator.Subtraction) {
4368 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4372 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4374 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4375 return new ClassCast (expr, l);
4379 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4381 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4384 // bool operator == (E x, E y);
4385 // bool operator != (E x, E y);
4386 // bool operator < (E x, E y);
4387 // bool operator > (E x, E y);
4388 // bool operator <= (E x, E y);
4389 // bool operator >= (E x, E y);
4391 // E operator & (E x, E y);
4392 // E operator | (E x, E y);
4393 // E operator ^ (E x, E y);
4396 if ((oper & Operator.ComparisonMask) != 0) {
4397 type = rc.BuiltinTypes.Bool;
4403 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4409 if (ltype == rtype) {
4413 var lifted = new Nullable.LiftedBinaryOperator (this);
4415 lifted.Right = right;
4416 return lifted.Resolve (rc);
4419 if (renum && !ltype.IsNullableType) {
4420 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4425 } else if (lenum && !rtype.IsNullableType) {
4426 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4434 // Now try lifted version of predefined operator
4436 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4437 if (nullable_type != null) {
4438 if (renum && !ltype.IsNullableType) {
4439 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4441 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4444 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4447 if ((oper & Operator.BitwiseMask) != 0)
4451 if ((oper & Operator.BitwiseMask) != 0)
4452 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4454 return CreateLiftedValueTypeResult (rc, rtype);
4458 var lifted = new Nullable.LiftedBinaryOperator (this);
4460 lifted.Right = right;
4461 return lifted.Resolve (rc);
4463 } else if (lenum && !rtype.IsNullableType) {
4464 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4466 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4469 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4472 if ((oper & Operator.BitwiseMask) != 0)
4476 if ((oper & Operator.BitwiseMask) != 0)
4477 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4479 return CreateLiftedValueTypeResult (rc, ltype);
4483 var lifted = new Nullable.LiftedBinaryOperator (this);
4485 lifted.Right = expr;
4486 return lifted.Resolve (rc);
4488 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4489 Nullable.Unwrap unwrap = null;
4490 if (left.IsNull || right.IsNull) {
4491 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4492 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4494 if ((oper & Operator.RelationalMask) != 0)
4495 return CreateLiftedValueTypeResult (rc, rtype);
4497 if ((oper & Operator.BitwiseMask) != 0)
4498 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4501 return CreateLiftedValueTypeResult (rc, left.Type);
4503 // Equality operators are valid between E? and null
4505 unwrap = new Nullable.Unwrap (right);
4507 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4511 if ((oper & Operator.BitwiseMask) != 0)
4516 var lifted = new Nullable.LiftedBinaryOperator (this);
4518 lifted.Right = right;
4519 lifted.UnwrapRight = unwrap;
4520 return lifted.Resolve (rc);
4522 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4523 Nullable.Unwrap unwrap = null;
4524 if (right.IsNull || left.IsNull) {
4525 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4526 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4528 if ((oper & Operator.RelationalMask) != 0)
4529 return CreateLiftedValueTypeResult (rc, ltype);
4531 if ((oper & Operator.BitwiseMask) != 0)
4532 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4535 return CreateLiftedValueTypeResult (rc, right.Type);
4537 // Equality operators are valid between E? and null
4539 unwrap = new Nullable.Unwrap (left);
4541 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4545 if ((oper & Operator.BitwiseMask) != 0)
4550 var lifted = new Nullable.LiftedBinaryOperator (this);
4552 lifted.UnwrapLeft = unwrap;
4553 lifted.Right = expr;
4554 return lifted.Resolve (rc);
4562 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4564 TypeSpec underlying_type;
4565 if (expr.Type.IsNullableType) {
4566 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4568 underlying_type = EnumSpec.GetUnderlyingType (nt);
4570 underlying_type = nt;
4571 } else if (expr.Type.IsEnum) {
4572 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4574 underlying_type = expr.Type;
4577 switch (underlying_type.BuiltinType) {
4578 case BuiltinTypeSpec.Type.SByte:
4579 case BuiltinTypeSpec.Type.Byte:
4580 case BuiltinTypeSpec.Type.Short:
4581 case BuiltinTypeSpec.Type.UShort:
4582 underlying_type = rc.BuiltinTypes.Int;
4586 if (expr.Type.IsNullableType || liftType)
4587 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4589 if (expr.Type == underlying_type)
4592 return EmptyCast.Create (expr, underlying_type);
4595 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4598 // U operator - (E e, E f)
4599 // E operator - (E e, U x) // Internal decomposition operator
4600 // E operator - (U x, E e) // Internal decomposition operator
4602 // E operator + (E e, U x)
4603 // E operator + (U x, E e)
4612 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4618 if (!enum_type.IsNullableType) {
4619 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4621 if (oper == Operator.Subtraction)
4622 expr = ConvertEnumSubtractionResult (rc, expr);
4624 expr = ConvertEnumAdditionalResult (expr, enum_type);
4626 enum_conversion = GetEnumResultCast (expr.Type);
4631 var nullable = rc.Module.PredefinedTypes.Nullable;
4634 // Don't try nullable version when nullable type is undefined
4636 if (!nullable.IsDefined)
4639 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4642 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4644 if (oper == Operator.Subtraction)
4645 expr = ConvertEnumSubtractionResult (rc, expr);
4647 expr = ConvertEnumAdditionalResult (expr, enum_type);
4649 enum_conversion = GetEnumResultCast (expr.Type);
4655 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4657 return EmptyCast.Create (expr, enumType);
4660 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4663 // Enumeration subtraction has different result type based on
4666 TypeSpec result_type;
4667 if (left.Type == right.Type) {
4668 var c = right as EnumConstant;
4669 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4671 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4672 // E which is not what expressions E - 1 or 0 - E return
4674 result_type = left.Type;
4676 result_type = left.Type.IsNullableType ?
4677 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4678 EnumSpec.GetUnderlyingType (left.Type);
4681 if (IsEnumOrNullableEnum (left.Type)) {
4682 result_type = left.Type;
4684 result_type = right.Type;
4687 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4688 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4691 return EmptyCast.Create (expr, result_type);
4694 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4696 if (type.IsNullableType)
4697 type = Nullable.NullableInfo.GetUnderlyingType (type);
4700 type = EnumSpec.GetUnderlyingType (type);
4702 switch (type.BuiltinType) {
4703 case BuiltinTypeSpec.Type.SByte:
4704 return ConvCast.Mode.I4_I1;
4705 case BuiltinTypeSpec.Type.Byte:
4706 return ConvCast.Mode.I4_U1;
4707 case BuiltinTypeSpec.Type.Short:
4708 return ConvCast.Mode.I4_I2;
4709 case BuiltinTypeSpec.Type.UShort:
4710 return ConvCast.Mode.I4_U2;
4717 // Equality operators rules
4719 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4722 type = ec.BuiltinTypes.Bool;
4723 bool no_arg_conv = false;
4725 if (!primitives_only) {
4728 // a, Both operands are reference-type values or the value null
4729 // b, One operand is a value of type T where T is a type-parameter and
4730 // the other operand is the value null. Furthermore T does not have the
4731 // value type constraint
4733 // LAMESPEC: Very confusing details in the specification, basically any
4734 // reference like type-parameter is allowed
4736 var tparam_l = l as TypeParameterSpec;
4737 var tparam_r = r as TypeParameterSpec;
4738 if (tparam_l != null) {
4739 if (right is NullLiteral) {
4740 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4743 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4747 if (!tparam_l.IsReferenceType)
4750 l = tparam_l.GetEffectiveBase ();
4751 left = new BoxedCast (left, l);
4752 } else if (left is NullLiteral && tparam_r == null) {
4753 if (TypeSpec.IsReferenceType (r))
4756 if (r.Kind == MemberKind.InternalCompilerType)
4760 if (tparam_r != null) {
4761 if (left is NullLiteral) {
4762 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4765 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4769 if (!tparam_r.IsReferenceType)
4772 r = tparam_r.GetEffectiveBase ();
4773 right = new BoxedCast (right, r);
4774 } else if (right is NullLiteral) {
4775 if (TypeSpec.IsReferenceType (l))
4778 if (l.Kind == MemberKind.InternalCompilerType)
4783 // LAMESPEC: method groups can be compared when they convert to other side delegate
4786 if (right.eclass == ExprClass.MethodGroup) {
4787 result = Convert.ImplicitConversion (ec, right, l, loc);
4793 } else if (r.IsDelegate && l != r) {
4796 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4797 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4804 no_arg_conv = l == r && !l.IsStruct;
4809 // bool operator != (string a, string b)
4810 // bool operator == (string a, string b)
4812 // bool operator != (Delegate a, Delegate b)
4813 // bool operator == (Delegate a, Delegate b)
4815 // bool operator != (bool a, bool b)
4816 // bool operator == (bool a, bool b)
4818 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4819 // they implement an implicit conversion to any of types above. This does
4820 // not apply when both operands are of same reference type
4822 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4823 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4828 // Now try lifted version of predefined operators
4830 if (no_arg_conv && !l.IsNullableType) {
4832 // Optimizes cases which won't match
4835 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4841 // The == and != operators permit one operand to be a value of a nullable
4842 // type and the other to be the null literal, even if no predefined or user-defined
4843 // operator (in unlifted or lifted form) exists for the operation.
4845 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4846 var lifted = new Nullable.LiftedBinaryOperator (this);
4848 lifted.Right = right;
4849 return lifted.Resolve (ec);
4854 // bool operator != (object a, object b)
4855 // bool operator == (object a, object b)
4857 // An explicit reference conversion exists from the
4858 // type of either operand to the type of the other operand.
4861 // Optimize common path
4863 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4866 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4867 !Convert.ExplicitReferenceConversionExists (r, l))
4870 // Reject allowed explicit conversions like int->object
4871 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4874 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4875 ec.Report.Warning (253, 2, loc,
4876 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4877 l.GetSignatureForError ());
4879 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4880 ec.Report.Warning (252, 2, loc,
4881 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4882 r.GetSignatureForError ());
4888 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4891 // bool operator == (void* x, void* y);
4892 // bool operator != (void* x, void* y);
4893 // bool operator < (void* x, void* y);
4894 // bool operator > (void* x, void* y);
4895 // bool operator <= (void* x, void* y);
4896 // bool operator >= (void* x, void* y);
4898 if ((oper & Operator.ComparisonMask) != 0) {
4901 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4908 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4914 type = ec.BuiltinTypes.Bool;
4918 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4922 // Build-in operators method overloading
4924 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4926 PredefinedOperator best_operator = null;
4927 TypeSpec l = left.Type;
4928 TypeSpec r = right.Type;
4929 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4931 foreach (PredefinedOperator po in operators) {
4932 if ((po.OperatorsMask & oper_mask) == 0)
4935 if (primitives_only) {
4936 if (!po.IsPrimitiveApplicable (l, r))
4939 if (!po.IsApplicable (ec, left, right))
4943 if (best_operator == null) {
4945 if (primitives_only)
4951 best_operator = po.ResolveBetterOperator (ec, best_operator);
4953 if (best_operator == null) {
4954 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4955 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4962 if (best_operator == null)
4965 return best_operator.ConvertResult (ec, this);
4969 // Optimize & constant expressions with 0 value
4971 Expression OptimizeAndOperation (Expression expr)
4973 Constant rc = right as Constant;
4974 Constant lc = left as Constant;
4975 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4977 // The result is a constant with side-effect
4979 Constant side_effect = rc == null ?
4980 new SideEffectConstant (lc, right, loc) :
4981 new SideEffectConstant (rc, left, loc);
4983 return ReducedExpression.Create (side_effect, expr);
4990 // Value types can be compared with the null literal because of the lifting
4991 // language rules. However the result is always true or false.
4993 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4995 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4996 type = rc.BuiltinTypes.Bool;
5000 // FIXME: Handle side effect constants
5001 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5003 if ((Oper & Operator.EqualityMask) != 0) {
5004 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5005 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5007 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5008 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5015 // Performs user-operator overloading
5017 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5019 Expression oper_expr;
5021 var op = ConvertBinaryToUserOperator (oper);
5023 if (l.IsNullableType)
5024 l = Nullable.NullableInfo.GetUnderlyingType (l);
5026 if (r.IsNullableType)
5027 r = Nullable.NullableInfo.GetUnderlyingType (r);
5029 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5030 IList<MemberSpec> right_operators = null;
5033 right_operators = MemberCache.GetUserOperator (r, op, false);
5034 if (right_operators == null && left_operators == null)
5036 } else if (left_operators == null) {
5040 Arguments args = new Arguments (2);
5041 Argument larg = new Argument (left);
5043 Argument rarg = new Argument (right);
5047 // User-defined operator implementations always take precedence
5048 // over predefined operator implementations
5050 if (left_operators != null && right_operators != null) {
5051 left_operators = CombineUserOperators (left_operators, right_operators);
5052 } else if (right_operators != null) {
5053 left_operators = right_operators;
5056 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5057 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5059 var res = new OverloadResolver (left_operators, restr, loc);
5061 var oper_method = res.ResolveOperator (rc, ref args);
5062 if (oper_method == null) {
5064 // Logical && and || cannot be lifted
5066 if ((oper & Operator.LogicalMask) != 0)
5070 // Apply lifted user operators only for liftable types. Implicit conversion
5071 // to nullable types is not allowed
5073 if (!IsLiftedOperatorApplicable ())
5076 // TODO: Cache the result in module container
5077 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5078 if (lifted_methods == null)
5081 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5083 oper_method = res.ResolveOperator (rc, ref args);
5084 if (oper_method == null)
5087 MethodSpec best_original = null;
5088 foreach (MethodSpec ms in left_operators) {
5089 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5095 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5097 // Expression trees use lifted notation in this case
5099 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5100 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5103 var ptypes = best_original.Parameters.Types;
5105 if (left.IsNull || right.IsNull) {
5107 // The lifted operator produces a null value if one or both operands are null
5109 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5110 type = oper_method.ReturnType;
5111 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5115 // The lifted operator produces the value false if one or both operands are null for
5116 // relational operators.
5118 if ((oper & Operator.RelationalMask) != 0) {
5120 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5121 // because return type is actually bool
5123 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5126 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5127 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5131 type = oper_method.ReturnType;
5132 var lifted = new Nullable.LiftedBinaryOperator (this);
5133 lifted.UserOperator = best_original;
5135 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5136 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5139 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5140 lifted.UnwrapRight = new Nullable.Unwrap (right);
5143 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5144 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5146 return lifted.Resolve (rc);
5149 if ((oper & Operator.LogicalMask) != 0) {
5150 // TODO: CreateExpressionTree is allocated every time
5151 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5152 oper == Operator.LogicalAnd, loc).Resolve (rc);
5154 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5157 this.left = larg.Expr;
5158 this.right = rarg.Expr;
5163 bool IsLiftedOperatorApplicable ()
5165 if (left.Type.IsNullableType) {
5166 if ((oper & Operator.EqualityMask) != 0)
5167 return !right.IsNull;
5172 if (right.Type.IsNullableType) {
5173 if ((oper & Operator.EqualityMask) != 0)
5174 return !left.IsNull;
5179 if (TypeSpec.IsValueType (left.Type))
5180 return right.IsNull;
5182 if (TypeSpec.IsValueType (right.Type))
5188 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5190 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5191 if (nullable_type == null)
5195 // Lifted operators permit predefined and user-defined operators that operate
5196 // on non-nullable value types to also be used with nullable forms of those types.
5197 // Lifted operators are constructed from predefined and user-defined operators
5198 // that meet certain requirements
5200 List<MemberSpec> lifted = null;
5201 foreach (MethodSpec oper in operators) {
5203 if ((Oper & Operator.ComparisonMask) != 0) {
5205 // Result type must be of type bool for lifted comparison operators
5207 rt = oper.ReturnType;
5208 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5211 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5217 var ptypes = oper.Parameters.Types;
5218 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5222 // LAMESPEC: I am not sure why but for equality operators to be lifted
5223 // both types have to match
5225 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5229 lifted = new List<MemberSpec> ();
5232 // The lifted form is constructed by adding a single ? modifier to each operand and
5233 // result type except for comparison operators where return type is bool
5236 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5238 var parameters = ParametersCompiled.CreateFullyResolved (
5239 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5240 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5242 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5243 rt, parameters, oper.Modifiers);
5245 lifted.Add (lifted_op);
5252 // Merge two sets of user operators into one, they are mostly distinguish
5253 // except when they share base type and it contains an operator
5255 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5257 var combined = new List<MemberSpec> (left.Count + right.Count);
5258 combined.AddRange (left);
5259 foreach (var r in right) {
5261 foreach (var l in left) {
5262 if (l.DeclaringType == r.DeclaringType) {
5275 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5277 if (c is IntegralConstant || c is CharConstant) {
5279 c.ConvertExplicitly (true, type);
5280 } catch (OverflowException) {
5281 ec.Report.Warning (652, 2, loc,
5282 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5283 type.GetSignatureForError ());
5289 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5290 /// context of a conditional bool expression. This function will return
5291 /// false if it is was possible to use EmitBranchable, or true if it was.
5293 /// The expression's code is generated, and we will generate a branch to `target'
5294 /// if the resulting expression value is equal to isTrue
5296 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5298 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5299 left = left.EmitToField (ec);
5301 if ((oper & Operator.LogicalMask) == 0) {
5302 right = right.EmitToField (ec);
5307 // This is more complicated than it looks, but its just to avoid
5308 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5309 // but on top of that we want for == and != to use a special path
5310 // if we are comparing against null
5312 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5313 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5316 // put the constant on the rhs, for simplicity
5318 if (left is Constant) {
5319 Expression swap = right;
5325 // brtrue/brfalse works with native int only
5327 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5328 left.EmitBranchable (ec, target, my_on_true);
5331 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5332 // right is a boolean, and it's not 'false' => it is 'true'
5333 left.EmitBranchable (ec, target, !my_on_true);
5337 } else if (oper == Operator.LogicalAnd) {
5340 Label tests_end = ec.DefineLabel ();
5342 left.EmitBranchable (ec, tests_end, false);
5343 right.EmitBranchable (ec, target, true);
5344 ec.MarkLabel (tests_end);
5347 // This optimizes code like this
5348 // if (true && i > 4)
5350 if (!(left is Constant))
5351 left.EmitBranchable (ec, target, false);
5353 if (!(right is Constant))
5354 right.EmitBranchable (ec, target, false);
5359 } else if (oper == Operator.LogicalOr){
5361 left.EmitBranchable (ec, target, true);
5362 right.EmitBranchable (ec, target, true);
5365 Label tests_end = ec.DefineLabel ();
5366 left.EmitBranchable (ec, tests_end, true);
5367 right.EmitBranchable (ec, target, false);
5368 ec.MarkLabel (tests_end);
5373 } else if ((oper & Operator.ComparisonMask) == 0) {
5374 base.EmitBranchable (ec, target, on_true);
5381 TypeSpec t = left.Type;
5382 bool is_float = IsFloat (t);
5383 bool is_unsigned = is_float || IsUnsigned (t);
5386 case Operator.Equality:
5388 ec.Emit (OpCodes.Beq, target);
5390 ec.Emit (OpCodes.Bne_Un, target);
5393 case Operator.Inequality:
5395 ec.Emit (OpCodes.Bne_Un, target);
5397 ec.Emit (OpCodes.Beq, target);
5400 case Operator.LessThan:
5402 if (is_unsigned && !is_float)
5403 ec.Emit (OpCodes.Blt_Un, target);
5405 ec.Emit (OpCodes.Blt, target);
5408 ec.Emit (OpCodes.Bge_Un, target);
5410 ec.Emit (OpCodes.Bge, target);
5413 case Operator.GreaterThan:
5415 if (is_unsigned && !is_float)
5416 ec.Emit (OpCodes.Bgt_Un, target);
5418 ec.Emit (OpCodes.Bgt, target);
5421 ec.Emit (OpCodes.Ble_Un, target);
5423 ec.Emit (OpCodes.Ble, target);
5426 case Operator.LessThanOrEqual:
5428 if (is_unsigned && !is_float)
5429 ec.Emit (OpCodes.Ble_Un, target);
5431 ec.Emit (OpCodes.Ble, target);
5434 ec.Emit (OpCodes.Bgt_Un, target);
5436 ec.Emit (OpCodes.Bgt, target);
5440 case Operator.GreaterThanOrEqual:
5442 if (is_unsigned && !is_float)
5443 ec.Emit (OpCodes.Bge_Un, target);
5445 ec.Emit (OpCodes.Bge, target);
5448 ec.Emit (OpCodes.Blt_Un, target);
5450 ec.Emit (OpCodes.Blt, target);
5453 throw new InternalErrorException (oper.ToString ());
5457 public override void Emit (EmitContext ec)
5459 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5460 left = left.EmitToField (ec);
5462 if ((oper & Operator.LogicalMask) == 0) {
5463 right = right.EmitToField (ec);
5468 // Handle short-circuit operators differently
5471 if ((oper & Operator.LogicalMask) != 0) {
5472 Label load_result = ec.DefineLabel ();
5473 Label end = ec.DefineLabel ();
5475 bool is_or = oper == Operator.LogicalOr;
5476 left.EmitBranchable (ec, load_result, is_or);
5478 ec.Emit (OpCodes.Br_S, end);
5480 ec.MarkLabel (load_result);
5481 ec.EmitInt (is_or ? 1 : 0);
5487 // Optimize zero-based operations which cannot be optimized at expression level
5489 if (oper == Operator.Subtraction) {
5490 var lc = left as IntegralConstant;
5491 if (lc != null && lc.IsDefaultValue) {
5493 ec.Emit (OpCodes.Neg);
5498 EmitOperator (ec, left, right);
5501 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5506 EmitOperatorOpcode (ec, oper, left.Type, right);
5509 // Emit result enumerable conversion this way because it's quite complicated get it
5510 // to resolved tree because expression tree cannot see it.
5512 if (enum_conversion != 0)
5513 ConvCast.Emit (ec, enum_conversion);
5516 public override void EmitSideEffect (EmitContext ec)
5518 if ((oper & Operator.LogicalMask) != 0 ||
5519 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5520 base.EmitSideEffect (ec);
5522 left.EmitSideEffect (ec);
5523 right.EmitSideEffect (ec);
5527 public override Expression EmitToField (EmitContext ec)
5529 if ((oper & Operator.LogicalMask) == 0) {
5530 var await_expr = left as Await;
5531 if (await_expr != null && right.IsSideEffectFree) {
5532 await_expr.Statement.EmitPrologue (ec);
5533 left = await_expr.Statement.GetResultExpression (ec);
5537 await_expr = right as Await;
5538 if (await_expr != null && left.IsSideEffectFree) {
5539 await_expr.Statement.EmitPrologue (ec);
5540 right = await_expr.Statement.GetResultExpression (ec);
5545 return base.EmitToField (ec);
5548 protected override void CloneTo (CloneContext clonectx, Expression t)
5550 Binary target = (Binary) t;
5552 target.left = left.Clone (clonectx);
5553 target.right = right.Clone (clonectx);
5556 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5558 Arguments binder_args = new Arguments (4);
5560 MemberAccess sle = new MemberAccess (new MemberAccess (
5561 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5563 CSharpBinderFlags flags = 0;
5564 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5565 flags = CSharpBinderFlags.CheckedContext;
5567 if ((oper & Operator.LogicalMask) != 0)
5568 flags |= CSharpBinderFlags.BinaryOperationLogical;
5570 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5571 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5572 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5573 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5575 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5578 public override Expression CreateExpressionTree (ResolveContext ec)
5580 return CreateExpressionTree (ec, null);
5583 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5586 bool lift_arg = false;
5589 case Operator.Addition:
5590 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5591 method_name = "AddChecked";
5593 method_name = "Add";
5595 case Operator.BitwiseAnd:
5596 method_name = "And";
5598 case Operator.BitwiseOr:
5601 case Operator.Division:
5602 method_name = "Divide";
5604 case Operator.Equality:
5605 method_name = "Equal";
5608 case Operator.ExclusiveOr:
5609 method_name = "ExclusiveOr";
5611 case Operator.GreaterThan:
5612 method_name = "GreaterThan";
5615 case Operator.GreaterThanOrEqual:
5616 method_name = "GreaterThanOrEqual";
5619 case Operator.Inequality:
5620 method_name = "NotEqual";
5623 case Operator.LeftShift:
5624 method_name = "LeftShift";
5626 case Operator.LessThan:
5627 method_name = "LessThan";
5630 case Operator.LessThanOrEqual:
5631 method_name = "LessThanOrEqual";
5634 case Operator.LogicalAnd:
5635 method_name = "AndAlso";
5637 case Operator.LogicalOr:
5638 method_name = "OrElse";
5640 case Operator.Modulus:
5641 method_name = "Modulo";
5643 case Operator.Multiply:
5644 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5645 method_name = "MultiplyChecked";
5647 method_name = "Multiply";
5649 case Operator.RightShift:
5650 method_name = "RightShift";
5652 case Operator.Subtraction:
5653 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5654 method_name = "SubtractChecked";
5656 method_name = "Subtract";
5660 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5663 Arguments args = new Arguments (2);
5664 args.Add (new Argument (left.CreateExpressionTree (ec)));
5665 args.Add (new Argument (right.CreateExpressionTree (ec)));
5666 if (method != null) {
5668 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5670 args.Add (new Argument (method));
5673 return CreateExpressionFactoryCall (ec, method_name, args);
5676 public override object Accept (StructuralVisitor visitor)
5678 return visitor.Visit (this);
5684 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5685 // b, c, d... may be strings or objects.
5687 public class StringConcat : Expression
5689 Arguments arguments;
5691 StringConcat (Location loc)
5694 arguments = new Arguments (2);
5697 public override bool ContainsEmitWithAwait ()
5699 return arguments.ContainsEmitWithAwait ();
5702 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5704 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5705 throw new ArgumentException ();
5707 var s = new StringConcat (loc);
5708 s.type = rc.BuiltinTypes.String;
5709 s.eclass = ExprClass.Value;
5711 s.Append (rc, left);
5712 s.Append (rc, right);
5716 public override Expression CreateExpressionTree (ResolveContext ec)
5718 Argument arg = arguments [0];
5719 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5723 // Creates nested calls tree from an array of arguments used for IL emit
5725 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5727 Arguments concat_args = new Arguments (2);
5728 Arguments add_args = new Arguments (3);
5730 concat_args.Add (left);
5731 add_args.Add (new Argument (left_etree));
5733 concat_args.Add (arguments [pos]);
5734 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5736 var methods = GetConcatMethodCandidates ();
5737 if (methods == null)
5740 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5741 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5745 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5747 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5748 if (++pos == arguments.Count)
5751 left = new Argument (new EmptyExpression (method.ReturnType));
5752 return CreateExpressionAddCall (ec, left, expr, pos);
5755 protected override Expression DoResolve (ResolveContext ec)
5760 void Append (ResolveContext rc, Expression operand)
5765 StringConstant sc = operand as StringConstant;
5767 if (arguments.Count != 0) {
5768 Argument last_argument = arguments [arguments.Count - 1];
5769 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5770 if (last_expr_constant != null) {
5771 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5777 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5779 StringConcat concat_oper = operand as StringConcat;
5780 if (concat_oper != null) {
5781 arguments.AddRange (concat_oper.arguments);
5786 arguments.Add (new Argument (operand));
5789 IList<MemberSpec> GetConcatMethodCandidates ()
5791 return MemberCache.FindMembers (type, "Concat", true);
5794 public override void Emit (EmitContext ec)
5796 // Optimize by removing any extra null arguments, they are no-op
5797 for (int i = 0; i < arguments.Count; ++i) {
5798 if (arguments[i].Expr is NullConstant)
5799 arguments.RemoveAt (i--);
5802 var members = GetConcatMethodCandidates ();
5803 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5804 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5805 if (method != null) {
5806 var call = new CallEmitter ();
5807 call.EmitPredefined (ec, method, arguments, false);
5811 public override void FlowAnalysis (FlowAnalysisContext fc)
5813 arguments.FlowAnalysis (fc);
5816 public override SLE.Expression MakeExpression (BuilderContext ctx)
5818 if (arguments.Count != 2)
5819 throw new NotImplementedException ("arguments.Count != 2");
5821 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5822 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5827 // User-defined conditional logical operator
5829 public class ConditionalLogicalOperator : UserOperatorCall
5831 readonly bool is_and;
5832 Expression oper_expr;
5834 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5835 : base (oper, arguments, expr_tree, loc)
5837 this.is_and = is_and;
5838 eclass = ExprClass.Unresolved;
5841 protected override Expression DoResolve (ResolveContext ec)
5843 AParametersCollection pd = oper.Parameters;
5844 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5845 ec.Report.Error (217, loc,
5846 "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",
5847 oper.GetSignatureForError ());
5851 Expression left_dup = new EmptyExpression (type);
5852 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5853 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5854 if (op_true == null || op_false == null) {
5855 ec.Report.Error (218, loc,
5856 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5857 type.GetSignatureForError (), oper.GetSignatureForError ());
5861 oper_expr = is_and ? op_false : op_true;
5862 eclass = ExprClass.Value;
5866 public override void Emit (EmitContext ec)
5868 Label end_target = ec.DefineLabel ();
5871 // Emit and duplicate left argument
5873 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5874 if (right_contains_await) {
5875 arguments[0] = arguments[0].EmitToField (ec, false);
5876 arguments[0].Expr.Emit (ec);
5878 arguments[0].Expr.Emit (ec);
5879 ec.Emit (OpCodes.Dup);
5880 arguments.RemoveAt (0);
5883 oper_expr.EmitBranchable (ec, end_target, true);
5887 if (right_contains_await) {
5889 // Special handling when right expression contains await and left argument
5890 // could not be left on stack before logical branch
5892 Label skip_left_load = ec.DefineLabel ();
5893 ec.Emit (OpCodes.Br_S, skip_left_load);
5894 ec.MarkLabel (end_target);
5895 arguments[0].Expr.Emit (ec);
5896 ec.MarkLabel (skip_left_load);
5898 ec.MarkLabel (end_target);
5903 public class PointerArithmetic : Expression {
5904 Expression left, right;
5905 readonly Binary.Operator op;
5908 // We assume that `l' is always a pointer
5910 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5919 public override bool ContainsEmitWithAwait ()
5921 throw new NotImplementedException ();
5924 public override Expression CreateExpressionTree (ResolveContext ec)
5926 Error_PointerInsideExpressionTree (ec);
5930 protected override Expression DoResolve (ResolveContext ec)
5932 eclass = ExprClass.Variable;
5934 var pc = left.Type as PointerContainer;
5935 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5936 Error_VoidPointerOperation (ec);
5943 public override void Emit (EmitContext ec)
5945 TypeSpec op_type = left.Type;
5947 // It must be either array or fixed buffer
5949 if (TypeManager.HasElementType (op_type)) {
5950 element = TypeManager.GetElementType (op_type);
5952 FieldExpr fe = left as FieldExpr;
5954 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5959 int size = BuiltinTypeSpec.GetSize(element);
5960 TypeSpec rtype = right.Type;
5962 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5964 // handle (pointer - pointer)
5968 ec.Emit (OpCodes.Sub);
5972 ec.Emit (OpCodes.Sizeof, element);
5975 ec.Emit (OpCodes.Div);
5977 ec.Emit (OpCodes.Conv_I8);
5980 // handle + and - on (pointer op int)
5982 Constant left_const = left as Constant;
5983 if (left_const != null) {
5985 // Optimize ((T*)null) pointer operations
5987 if (left_const.IsDefaultValue) {
5988 left = EmptyExpression.Null;
5996 var right_const = right as Constant;
5997 if (right_const != null) {
5999 // Optimize 0-based arithmetic
6001 if (right_const.IsDefaultValue)
6005 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6007 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6009 // TODO: Should be the checks resolve context sensitive?
6010 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6011 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6017 if (right_const == null) {
6018 switch (rtype.BuiltinType) {
6019 case BuiltinTypeSpec.Type.SByte:
6020 case BuiltinTypeSpec.Type.Byte:
6021 case BuiltinTypeSpec.Type.Short:
6022 case BuiltinTypeSpec.Type.UShort:
6023 case BuiltinTypeSpec.Type.Int:
6024 ec.Emit (OpCodes.Conv_I);
6026 case BuiltinTypeSpec.Type.UInt:
6027 ec.Emit (OpCodes.Conv_U);
6032 if (right_const == null && size != 1){
6034 ec.Emit (OpCodes.Sizeof, element);
6037 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6038 ec.Emit (OpCodes.Conv_I8);
6040 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6043 if (left_const == null) {
6044 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6045 ec.Emit (OpCodes.Conv_I);
6046 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6047 ec.Emit (OpCodes.Conv_U);
6049 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6056 // A boolean-expression is an expression that yields a result
6059 public class BooleanExpression : ShimExpression
6061 public BooleanExpression (Expression expr)
6064 this.loc = expr.Location;
6067 public override Expression CreateExpressionTree (ResolveContext ec)
6069 // TODO: We should emit IsTrue (v4) instead of direct user operator
6070 // call but that would break csc compatibility
6071 return base.CreateExpressionTree (ec);
6074 protected override Expression DoResolve (ResolveContext ec)
6076 // A boolean-expression is required to be of a type
6077 // that can be implicitly converted to bool or of
6078 // a type that implements operator true
6080 expr = expr.Resolve (ec);
6084 Assign ass = expr as Assign;
6085 if (ass != null && ass.Source is Constant) {
6086 ec.Report.Warning (665, 3, loc,
6087 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6090 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6093 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6094 Arguments args = new Arguments (1);
6095 args.Add (new Argument (expr));
6096 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6099 type = ec.BuiltinTypes.Bool;
6100 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6101 if (converted != null)
6105 // If no implicit conversion to bool exists, try using `operator true'
6107 converted = GetOperatorTrue (ec, expr, loc);
6108 if (converted == null) {
6109 expr.Error_ValueCannotBeConverted (ec, type, false);
6116 public override object Accept (StructuralVisitor visitor)
6118 return visitor.Visit (this);
6122 public class BooleanExpressionFalse : Unary
6124 public BooleanExpressionFalse (Expression expr)
6125 : base (Operator.LogicalNot, expr, expr.Location)
6129 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6131 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6136 /// Implements the ternary conditional operator (?:)
6138 public class Conditional : Expression {
6139 Expression expr, true_expr, false_expr;
6141 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6144 this.true_expr = true_expr;
6145 this.false_expr = false_expr;
6151 public Expression Expr {
6157 public Expression TrueExpr {
6163 public Expression FalseExpr {
6171 public override bool ContainsEmitWithAwait ()
6173 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6176 public override Expression CreateExpressionTree (ResolveContext ec)
6178 Arguments args = new Arguments (3);
6179 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6180 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6181 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6182 return CreateExpressionFactoryCall (ec, "Condition", args);
6185 protected override Expression DoResolve (ResolveContext ec)
6187 expr = expr.Resolve (ec);
6188 true_expr = true_expr.Resolve (ec);
6189 false_expr = false_expr.Resolve (ec);
6191 if (true_expr == null || false_expr == null || expr == null)
6194 eclass = ExprClass.Value;
6195 TypeSpec true_type = true_expr.Type;
6196 TypeSpec false_type = false_expr.Type;
6200 // First, if an implicit conversion exists from true_expr
6201 // to false_expr, then the result type is of type false_expr.Type
6203 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6204 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6205 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6207 // Check if both can convert implicitly to each other's type
6211 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6212 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6214 // LAMESPEC: There seems to be hardcoded promotition to int type when
6215 // both sides are numeric constants and one side is int constant and
6216 // other side is numeric constant convertible to int.
6218 // var res = condition ? (short)1 : 1;
6220 // Type of res is int even if according to the spec the conversion is
6221 // ambiguous because 1 literal can be converted to short.
6223 if (conv_false_expr != null) {
6224 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6226 conv_false_expr = null;
6227 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6228 conv_false_expr = null;
6232 if (conv_false_expr != null) {
6233 ec.Report.Error (172, true_expr.Location,
6234 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6235 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6240 if (true_expr.Type != type)
6241 true_expr = EmptyCast.Create (true_expr, type);
6242 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6245 if (false_type != InternalType.ErrorType) {
6246 ec.Report.Error (173, true_expr.Location,
6247 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6248 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6254 Constant c = expr as Constant;
6256 bool is_false = c.IsDefaultValue;
6259 // Don't issue the warning for constant expressions
6261 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6262 // CSC: Missing warning
6263 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6266 return ReducedExpression.Create (
6267 is_false ? false_expr : true_expr, this,
6268 false_expr is Constant && true_expr is Constant).Resolve (ec);
6274 public override void Emit (EmitContext ec)
6276 Label false_target = ec.DefineLabel ();
6277 Label end_target = ec.DefineLabel ();
6279 expr.EmitBranchable (ec, false_target, false);
6280 true_expr.Emit (ec);
6283 // Verifier doesn't support interface merging. When there are two types on
6284 // the stack without common type hint and the common type is an interface.
6285 // Use temporary local to give verifier hint on what type to unify the stack
6287 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6288 var temp = ec.GetTemporaryLocal (type);
6289 ec.Emit (OpCodes.Stloc, temp);
6290 ec.Emit (OpCodes.Ldloc, temp);
6291 ec.FreeTemporaryLocal (temp, type);
6294 ec.Emit (OpCodes.Br, end_target);
6295 ec.MarkLabel (false_target);
6296 false_expr.Emit (ec);
6297 ec.MarkLabel (end_target);
6300 public override void FlowAnalysis (FlowAnalysisContext fc)
6302 expr.FlowAnalysisConditional (fc);
6303 var expr_true = fc.DefiniteAssignmentOnTrue;
6304 var expr_false = fc.DefiniteAssignmentOnFalse;
6306 fc.BranchDefiniteAssignment (expr_true);
6307 true_expr.FlowAnalysis (fc);
6308 var true_fc = fc.DefiniteAssignment;
6310 fc.BranchDefiniteAssignment (expr_false);
6311 false_expr.FlowAnalysis (fc);
6313 fc.DefiniteAssignment &= true_fc;
6316 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6318 expr.FlowAnalysisConditional (fc);
6319 var expr_true = fc.DefiniteAssignmentOnTrue;
6320 var expr_false = fc.DefiniteAssignmentOnFalse;
6322 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6323 true_expr.FlowAnalysisConditional (fc);
6324 var true_fc = fc.DefiniteAssignment;
6325 var true_da_true = fc.DefiniteAssignmentOnTrue;
6326 var true_da_false = fc.DefiniteAssignmentOnFalse;
6328 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6329 false_expr.FlowAnalysisConditional (fc);
6331 fc.DefiniteAssignment &= true_fc;
6332 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6333 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6336 protected override void CloneTo (CloneContext clonectx, Expression t)
6338 Conditional target = (Conditional) t;
6340 target.expr = expr.Clone (clonectx);
6341 target.true_expr = true_expr.Clone (clonectx);
6342 target.false_expr = false_expr.Clone (clonectx);
6346 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6348 LocalTemporary temp;
6351 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6352 public abstract void SetHasAddressTaken ();
6354 public abstract bool IsLockedByStatement { get; set; }
6356 public abstract bool IsFixed { get; }
6357 public abstract bool IsRef { get; }
6358 public abstract string Name { get; }
6361 // Variable IL data, it has to be protected to encapsulate hoisted variables
6363 protected abstract ILocalVariable Variable { get; }
6366 // Variable flow-analysis data
6368 public abstract VariableInfo VariableInfo { get; }
6371 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6373 HoistedVariable hv = GetHoistedVariable (ec);
6375 hv.AddressOf (ec, mode);
6379 Variable.EmitAddressOf (ec);
6382 public override bool ContainsEmitWithAwait ()
6387 public override Expression CreateExpressionTree (ResolveContext ec)
6389 HoistedVariable hv = GetHoistedVariable (ec);
6391 return hv.CreateExpressionTree ();
6393 Arguments arg = new Arguments (1);
6394 arg.Add (new Argument (this));
6395 return CreateExpressionFactoryCall (ec, "Constant", arg);
6398 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6400 if (IsLockedByStatement) {
6401 rc.Report.Warning (728, 2, loc,
6402 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6409 public override void Emit (EmitContext ec)
6414 public override void EmitSideEffect (EmitContext ec)
6420 // This method is used by parameters that are references, that are
6421 // being passed as references: we only want to pass the pointer (that
6422 // is already stored in the parameter, not the address of the pointer,
6423 // and not the value of the variable).
6425 public void EmitLoad (EmitContext ec)
6430 public void Emit (EmitContext ec, bool leave_copy)
6432 HoistedVariable hv = GetHoistedVariable (ec);
6434 hv.Emit (ec, leave_copy);
6442 // If we are a reference, we loaded on the stack a pointer
6443 // Now lets load the real value
6445 ec.EmitLoadFromPtr (type);
6449 ec.Emit (OpCodes.Dup);
6452 temp = new LocalTemporary (Type);
6458 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6459 bool prepare_for_load)
6461 HoistedVariable hv = GetHoistedVariable (ec);
6463 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6467 New n_source = source as New;
6468 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6469 if (!n_source.Emit (ec, this)) {
6473 ec.EmitLoadFromPtr (type);
6485 ec.Emit (OpCodes.Dup);
6487 temp = new LocalTemporary (Type);
6493 ec.EmitStoreFromPtr (type);
6495 Variable.EmitAssign (ec);
6503 public override Expression EmitToField (EmitContext ec)
6505 HoistedVariable hv = GetHoistedVariable (ec);
6507 return hv.EmitToField (ec);
6510 return base.EmitToField (ec);
6513 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6515 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6518 public HoistedVariable GetHoistedVariable (EmitContext ec)
6520 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6523 public override string GetSignatureForError ()
6528 public bool IsHoisted {
6529 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6534 // Resolved reference to a local variable
6536 public class LocalVariableReference : VariableReference
6538 public LocalVariable local_info;
6540 public LocalVariableReference (LocalVariable li, Location l)
6542 this.local_info = li;
6546 public override VariableInfo VariableInfo {
6547 get { return local_info.VariableInfo; }
6550 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6552 return local_info.HoistedVariant;
6558 // A local variable is always fixed
6560 public override bool IsFixed {
6566 public override bool IsLockedByStatement {
6568 return local_info.IsLocked;
6571 local_info.IsLocked = value;
6575 public override bool IsRef {
6576 get { return false; }
6579 public override string Name {
6580 get { return local_info.Name; }
6585 public override void FlowAnalysis (FlowAnalysisContext fc)
6587 VariableInfo variable_info = VariableInfo;
6588 if (variable_info == null)
6591 if (fc.IsDefinitelyAssigned (variable_info))
6594 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6595 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6598 public override void SetHasAddressTaken ()
6600 local_info.SetHasAddressTaken ();
6603 void DoResolveBase (ResolveContext ec)
6605 eclass = ExprClass.Variable;
6606 type = local_info.Type;
6609 // If we are referencing a variable from the external block
6610 // flag it for capturing
6612 if (ec.MustCaptureVariable (local_info)) {
6613 if (local_info.AddressTaken) {
6614 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6615 } else if (local_info.IsFixed) {
6616 ec.Report.Error (1764, loc,
6617 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6618 GetSignatureForError ());
6621 if (ec.IsVariableCapturingRequired) {
6622 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6623 storey.CaptureLocalVariable (ec, local_info);
6628 protected override Expression DoResolve (ResolveContext ec)
6630 local_info.SetIsUsed ();
6634 if (local_info.Type == InternalType.VarOutType) {
6635 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6636 GetSignatureForError ());
6638 type = InternalType.ErrorType;
6644 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6647 // Don't be too pedantic when variable is used as out param or for some broken code
6648 // which uses property/indexer access to run some initialization
6650 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6651 local_info.SetIsUsed ();
6653 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6654 if (rhs == EmptyExpression.LValueMemberAccess) {
6655 // CS1654 already reported
6659 if (rhs == EmptyExpression.OutAccess) {
6660 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6661 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6662 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6663 } else if (rhs == EmptyExpression.UnaryAddress) {
6664 code = 459; msg = "Cannot take the address of {1} `{0}'";
6666 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6668 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6672 if (eclass == ExprClass.Unresolved)
6675 return base.DoResolveLValue (ec, rhs);
6678 public override int GetHashCode ()
6680 return local_info.GetHashCode ();
6683 public override bool Equals (object obj)
6685 LocalVariableReference lvr = obj as LocalVariableReference;
6689 return local_info == lvr.local_info;
6692 protected override ILocalVariable Variable {
6693 get { return local_info; }
6696 public override string ToString ()
6698 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6701 protected override void CloneTo (CloneContext clonectx, Expression t)
6708 /// This represents a reference to a parameter in the intermediate
6711 public class ParameterReference : VariableReference
6713 protected ParametersBlock.ParameterInfo pi;
6715 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6723 public override bool IsLockedByStatement {
6728 pi.IsLocked = value;
6732 public override bool IsRef {
6733 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6736 bool HasOutModifier {
6737 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6740 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6742 return pi.Parameter.HoistedVariant;
6746 // A ref or out parameter is classified as a moveable variable, even
6747 // if the argument given for the parameter is a fixed variable
6749 public override bool IsFixed {
6750 get { return !IsRef; }
6753 public override string Name {
6754 get { return Parameter.Name; }
6757 public Parameter Parameter {
6758 get { return pi.Parameter; }
6761 public override VariableInfo VariableInfo {
6762 get { return pi.VariableInfo; }
6765 protected override ILocalVariable Variable {
6766 get { return Parameter; }
6771 public override void AddressOf (EmitContext ec, AddressOp mode)
6774 // ParameterReferences might already be a reference
6781 base.AddressOf (ec, mode);
6784 public override void SetHasAddressTaken ()
6786 Parameter.HasAddressTaken = true;
6789 bool DoResolveBase (ResolveContext ec)
6791 if (eclass != ExprClass.Unresolved)
6794 type = pi.ParameterType;
6795 eclass = ExprClass.Variable;
6798 // If we are referencing a parameter from the external block
6799 // flag it for capturing
6801 if (ec.MustCaptureVariable (pi)) {
6802 if (Parameter.HasAddressTaken)
6803 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6806 ec.Report.Error (1628, loc,
6807 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6808 Name, ec.CurrentAnonymousMethod.ContainerType);
6811 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6812 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6813 storey.CaptureParameter (ec, pi, this);
6820 public override int GetHashCode ()
6822 return Name.GetHashCode ();
6825 public override bool Equals (object obj)
6827 ParameterReference pr = obj as ParameterReference;
6831 return Name == pr.Name;
6834 protected override void CloneTo (CloneContext clonectx, Expression target)
6840 public override Expression CreateExpressionTree (ResolveContext ec)
6842 HoistedVariable hv = GetHoistedVariable (ec);
6844 return hv.CreateExpressionTree ();
6846 return Parameter.ExpressionTreeVariableReference ();
6849 protected override Expression DoResolve (ResolveContext ec)
6851 if (!DoResolveBase (ec))
6857 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6859 if (!DoResolveBase (ec))
6862 if (Parameter.HoistedVariant != null)
6863 Parameter.HoistedVariant.IsAssigned = true;
6865 return base.DoResolveLValue (ec, right_side);
6868 public override void FlowAnalysis (FlowAnalysisContext fc)
6870 VariableInfo variable_info = VariableInfo;
6871 if (variable_info == null)
6874 if (fc.IsDefinitelyAssigned (variable_info))
6877 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6878 fc.SetVariableAssigned (variable_info);
6883 /// Invocation of methods or delegates.
6885 public class Invocation : ExpressionStatement
6887 public class Predefined : Invocation
6889 public Predefined (MethodGroupExpr expr, Arguments arguments)
6890 : base (expr, arguments)
6895 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6897 mg.BestCandidate.CheckObsoleteness (rc, loc);
6903 protected Arguments arguments;
6904 protected Expression expr;
6905 protected MethodGroupExpr mg;
6906 bool conditional_access_receiver;
6908 public Invocation (Expression expr, Arguments arguments)
6911 this.arguments = arguments;
6913 loc = expr.Location;
6918 public Arguments Arguments {
6924 public Expression Exp {
6930 public MethodGroupExpr MethodGroup {
6936 public override Location StartLocation {
6938 return expr.StartLocation;
6944 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6946 if (MethodGroup == null)
6949 var candidate = MethodGroup.BestCandidate;
6950 if (candidate == null || !(candidate.IsStatic || Exp is This))
6953 var args_count = arguments == null ? 0 : arguments.Count;
6954 if (args_count != body.Parameters.Count)
6957 var lambda_parameters = body.Block.Parameters.FixedParameters;
6958 for (int i = 0; i < args_count; ++i) {
6959 var pr = arguments[i].Expr as ParameterReference;
6963 if (lambda_parameters[i] != pr.Parameter)
6966 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6970 var emg = MethodGroup as ExtensionMethodGroupExpr;
6972 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6973 if (candidate.IsGeneric) {
6974 var targs = new TypeExpression [candidate.Arity];
6975 for (int i = 0; i < targs.Length; ++i) {
6976 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6979 mg.SetTypeArguments (null, new TypeArguments (targs));
6988 protected override void CloneTo (CloneContext clonectx, Expression t)
6990 Invocation target = (Invocation) t;
6992 if (arguments != null)
6993 target.arguments = arguments.Clone (clonectx);
6995 target.expr = expr.Clone (clonectx);
6998 public override bool ContainsEmitWithAwait ()
7000 if (arguments != null && arguments.ContainsEmitWithAwait ())
7003 return mg.ContainsEmitWithAwait ();
7006 public override Expression CreateExpressionTree (ResolveContext ec)
7008 Expression instance = mg.IsInstance ?
7009 mg.InstanceExpression.CreateExpressionTree (ec) :
7010 new NullLiteral (loc);
7012 var args = Arguments.CreateForExpressionTree (ec, arguments,
7014 mg.CreateExpressionTree (ec));
7016 return CreateExpressionFactoryCall (ec, "Call", args);
7019 void ResolveConditionalAccessReceiver (ResolveContext rc)
7021 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7022 conditional_access_receiver = true;
7026 bool statement_resolve;
7027 public override ExpressionStatement ResolveStatement (BlockContext bc)
7029 statement_resolve = true;
7030 var es = base.ResolveStatement (bc);
7031 statement_resolve = false;
7036 protected override Expression DoResolve (ResolveContext rc)
7038 ResolveConditionalAccessReceiver (rc);
7039 return DoResolveInvocation (rc);
7042 Expression DoResolveInvocation (ResolveContext ec)
7044 Expression member_expr;
7045 var atn = expr as ATypeNameExpression;
7047 var flags = default (ResolveContext.FlagsHandle);
7048 if (conditional_access_receiver)
7049 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7052 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7053 if (member_expr != null) {
7054 var name_of = member_expr as NameOf;
7055 if (name_of != null) {
7056 return name_of.ResolveOverload (ec, arguments);
7059 member_expr = member_expr.Resolve (ec);
7062 member_expr = expr.Resolve (ec);
7065 if (conditional_access_receiver)
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 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7077 arguments.Resolve (ec, out dynamic_arg);
7081 TypeSpec expr_type = member_expr.Type;
7082 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7083 return DoResolveDynamic (ec, member_expr);
7085 mg = member_expr as MethodGroupExpr;
7086 Expression invoke = null;
7089 if (expr_type != null && expr_type.IsDelegate) {
7090 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7091 invoke = invoke.Resolve (ec);
7092 if (invoke == null || !dynamic_arg)
7095 if (member_expr is RuntimeValueExpression) {
7096 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7097 member_expr.Type.GetSignatureForError ());
7101 MemberExpr me = member_expr as MemberExpr;
7103 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7107 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7108 member_expr.GetSignatureForError ());
7113 if (invoke == null) {
7114 mg = DoResolveOverload (ec);
7120 return DoResolveDynamic (ec, member_expr);
7122 var method = mg.BestCandidate;
7123 type = mg.BestCandidateReturnType;
7124 if (conditional_access_receiver && !statement_resolve)
7125 type = LiftMemberType (ec, type);
7127 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7129 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7131 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7135 IsSpecialMethodInvocation (ec, method, loc);
7137 eclass = ExprClass.Value;
7141 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7144 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7146 args = dmb.Arguments;
7147 if (arguments != null)
7148 args.AddRange (arguments);
7149 } else if (mg == null) {
7150 if (arguments == null)
7151 args = new Arguments (1);
7155 args.Insert (0, new Argument (memberExpr));
7159 ec.Report.Error (1971, loc,
7160 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7165 if (arguments == null)
7166 args = new Arguments (1);
7170 MemberAccess ma = expr as MemberAccess;
7172 var inst = mg.InstanceExpression;
7173 var left_type = inst as TypeExpr;
7174 if (left_type != null) {
7175 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7176 } else if (inst != null) {
7178 // Any value type has to be pass as by-ref to get back the same
7179 // instance on which the member was called
7181 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7182 Argument.AType.Ref : Argument.AType.None;
7183 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7185 } else { // is SimpleName
7186 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7187 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7189 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7194 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7197 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7199 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7202 public override void FlowAnalysis (FlowAnalysisContext fc)
7204 if (mg.IsConditionallyExcluded)
7207 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7209 mg.FlowAnalysis (fc);
7211 if (arguments != null)
7212 arguments.FlowAnalysis (fc);
7214 if (conditional_access_receiver)
7215 fc.DefiniteAssignment = da;
7218 public override string GetSignatureForError ()
7220 return mg.GetSignatureForError ();
7223 public override bool HasConditionalAccess ()
7225 return expr.HasConditionalAccess ();
7229 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7230 // or the type dynamic, then the member is invocable
7232 public static bool IsMemberInvocable (MemberSpec member)
7234 switch (member.Kind) {
7235 case MemberKind.Event:
7237 case MemberKind.Field:
7238 case MemberKind.Property:
7239 var m = member as IInterfaceMemberSpec;
7240 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7246 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7248 if (!method.IsReservedMethod)
7251 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7254 ec.Report.SymbolRelatedToPreviousError (method);
7255 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7256 method.GetSignatureForError ());
7261 public override void Emit (EmitContext ec)
7263 if (mg.IsConditionallyExcluded)
7266 if (conditional_access_receiver)
7267 mg.EmitCall (ec, arguments, type, false);
7269 mg.EmitCall (ec, arguments, false);
7272 public override void EmitStatement (EmitContext ec)
7274 if (mg.IsConditionallyExcluded)
7277 if (conditional_access_receiver)
7278 mg.EmitCall (ec, arguments, type, true);
7280 mg.EmitCall (ec, arguments, true);
7283 public override SLE.Expression MakeExpression (BuilderContext ctx)
7285 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7288 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7291 throw new NotSupportedException ();
7293 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7294 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7298 public override object Accept (StructuralVisitor visitor)
7300 return visitor.Visit (this);
7305 // Implements simple new expression
7307 public class New : ExpressionStatement, IMemoryLocation
7309 protected Arguments arguments;
7312 // During bootstrap, it contains the RequestedType,
7313 // but if `type' is not null, it *might* contain a NewDelegate
7314 // (because of field multi-initialization)
7316 protected Expression RequestedType;
7318 protected MethodSpec method;
7320 public New (Expression requested_type, Arguments arguments, Location l)
7322 RequestedType = requested_type;
7323 this.arguments = arguments;
7328 public Arguments Arguments {
7335 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7337 public bool IsGeneratedStructConstructor {
7339 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7343 public Expression TypeExpression {
7345 return RequestedType;
7352 /// Converts complex core type syntax like 'new int ()' to simple constant
7354 public static Constant Constantify (TypeSpec t, Location loc)
7356 switch (t.BuiltinType) {
7357 case BuiltinTypeSpec.Type.Int:
7358 return new IntConstant (t, 0, loc);
7359 case BuiltinTypeSpec.Type.UInt:
7360 return new UIntConstant (t, 0, loc);
7361 case BuiltinTypeSpec.Type.Long:
7362 return new LongConstant (t, 0, loc);
7363 case BuiltinTypeSpec.Type.ULong:
7364 return new ULongConstant (t, 0, loc);
7365 case BuiltinTypeSpec.Type.Float:
7366 return new FloatConstant (t, 0, loc);
7367 case BuiltinTypeSpec.Type.Double:
7368 return new DoubleConstant (t, 0, loc);
7369 case BuiltinTypeSpec.Type.Short:
7370 return new ShortConstant (t, 0, loc);
7371 case BuiltinTypeSpec.Type.UShort:
7372 return new UShortConstant (t, 0, loc);
7373 case BuiltinTypeSpec.Type.SByte:
7374 return new SByteConstant (t, 0, loc);
7375 case BuiltinTypeSpec.Type.Byte:
7376 return new ByteConstant (t, 0, loc);
7377 case BuiltinTypeSpec.Type.Char:
7378 return new CharConstant (t, '\0', loc);
7379 case BuiltinTypeSpec.Type.Bool:
7380 return new BoolConstant (t, false, loc);
7381 case BuiltinTypeSpec.Type.Decimal:
7382 return new DecimalConstant (t, 0, loc);
7386 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7388 if (t.IsNullableType)
7389 return Nullable.LiftedNull.Create (t, loc);
7394 public override bool ContainsEmitWithAwait ()
7396 return arguments != null && arguments.ContainsEmitWithAwait ();
7400 // Checks whether the type is an interface that has the
7401 // [ComImport, CoClass] attributes and must be treated
7404 public Expression CheckComImport (ResolveContext ec)
7406 if (!type.IsInterface)
7410 // Turn the call into:
7411 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7413 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7414 if (real_class == null)
7417 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7418 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7419 return cast.Resolve (ec);
7422 public override Expression CreateExpressionTree (ResolveContext ec)
7425 if (method == null) {
7426 args = new Arguments (1);
7427 args.Add (new Argument (new TypeOf (type, loc)));
7429 args = Arguments.CreateForExpressionTree (ec,
7430 arguments, new TypeOfMethod (method, loc));
7433 return CreateExpressionFactoryCall (ec, "New", args);
7436 protected override Expression DoResolve (ResolveContext ec)
7438 type = RequestedType.ResolveAsType (ec);
7442 eclass = ExprClass.Value;
7444 if (type.IsPointer) {
7445 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7446 type.GetSignatureForError ());
7450 if (arguments == null) {
7451 Constant c = Constantify (type, RequestedType.Location);
7453 return ReducedExpression.Create (c, this);
7456 if (type.IsDelegate) {
7457 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7460 var tparam = type as TypeParameterSpec;
7461 if (tparam != null) {
7463 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7464 // where type parameter constraint is inflated to struct
7466 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7467 ec.Report.Error (304, loc,
7468 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7469 type.GetSignatureForError ());
7472 if ((arguments != null) && (arguments.Count != 0)) {
7473 ec.Report.Error (417, loc,
7474 "`{0}': cannot provide arguments when creating an instance of a variable type",
7475 type.GetSignatureForError ());
7481 if (type.IsStatic) {
7482 ec.Report.SymbolRelatedToPreviousError (type);
7483 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7487 if (type.IsInterface || type.IsAbstract){
7488 if (!TypeManager.IsGenericType (type)) {
7489 RequestedType = CheckComImport (ec);
7490 if (RequestedType != null)
7491 return RequestedType;
7494 ec.Report.SymbolRelatedToPreviousError (type);
7495 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7500 if (arguments != null) {
7501 arguments.Resolve (ec, out dynamic);
7506 method = ConstructorLookup (ec, type, ref arguments, loc);
7509 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7510 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7516 void DoEmitTypeParameter (EmitContext ec)
7518 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7522 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7523 ec.Emit (OpCodes.Call, ctor_factory);
7527 // This Emit can be invoked in two contexts:
7528 // * As a mechanism that will leave a value on the stack (new object)
7529 // * As one that wont (init struct)
7531 // If we are dealing with a ValueType, we have a few
7532 // situations to deal with:
7534 // * The target is a ValueType, and we have been provided
7535 // the instance (this is easy, we are being assigned).
7537 // * The target of New is being passed as an argument,
7538 // to a boxing operation or a function that takes a
7541 // In this case, we need to create a temporary variable
7542 // that is the argument of New.
7544 // Returns whether a value is left on the stack
7546 // *** Implementation note ***
7548 // To benefit from this optimization, each assignable expression
7549 // has to manually cast to New and call this Emit.
7551 // TODO: It's worth to implement it for arrays and fields
7553 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7555 bool is_value_type = type.IsStructOrEnum;
7556 VariableReference vr = target as VariableReference;
7558 if (target != null && is_value_type && (vr != null || method == null)) {
7559 target.AddressOf (ec, AddressOp.Store);
7560 } else if (vr != null && vr.IsRef) {
7564 if (arguments != null) {
7565 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7566 arguments = arguments.Emit (ec, false, true);
7568 arguments.Emit (ec);
7571 if (is_value_type) {
7572 if (method == null) {
7573 ec.Emit (OpCodes.Initobj, type);
7578 ec.MarkCallEntry (loc);
7579 ec.Emit (OpCodes.Call, method);
7584 if (type is TypeParameterSpec) {
7585 DoEmitTypeParameter (ec);
7589 ec.MarkCallEntry (loc);
7590 ec.Emit (OpCodes.Newobj, method);
7594 public override void Emit (EmitContext ec)
7596 LocalTemporary v = null;
7597 if (method == null && type.IsStructOrEnum) {
7598 // TODO: Use temporary variable from pool
7599 v = new LocalTemporary (type);
7606 public override void EmitStatement (EmitContext ec)
7608 LocalTemporary v = null;
7609 if (method == null && TypeSpec.IsValueType (type)) {
7610 // TODO: Use temporary variable from pool
7611 v = new LocalTemporary (type);
7615 ec.Emit (OpCodes.Pop);
7618 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7623 public override void FlowAnalysis (FlowAnalysisContext fc)
7625 if (arguments != null)
7626 arguments.FlowAnalysis (fc);
7629 public void AddressOf (EmitContext ec, AddressOp mode)
7631 EmitAddressOf (ec, mode);
7634 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7636 LocalTemporary value_target = new LocalTemporary (type);
7638 if (type is TypeParameterSpec) {
7639 DoEmitTypeParameter (ec);
7640 value_target.Store (ec);
7641 value_target.AddressOf (ec, mode);
7642 return value_target;
7645 value_target.AddressOf (ec, AddressOp.Store);
7647 if (method == null) {
7648 ec.Emit (OpCodes.Initobj, type);
7650 if (arguments != null)
7651 arguments.Emit (ec);
7653 ec.Emit (OpCodes.Call, method);
7656 value_target.AddressOf (ec, mode);
7657 return value_target;
7660 protected override void CloneTo (CloneContext clonectx, Expression t)
7662 New target = (New) t;
7664 target.RequestedType = RequestedType.Clone (clonectx);
7665 if (arguments != null){
7666 target.arguments = arguments.Clone (clonectx);
7670 public override SLE.Expression MakeExpression (BuilderContext ctx)
7673 return base.MakeExpression (ctx);
7675 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7679 public override object Accept (StructuralVisitor visitor)
7681 return visitor.Visit (this);
7686 // Array initializer expression, the expression is allowed in
7687 // variable or field initialization only which makes it tricky as
7688 // the type has to be infered based on the context either from field
7689 // type or variable type (think of multiple declarators)
7691 public class ArrayInitializer : Expression
7693 List<Expression> elements;
7694 BlockVariable variable;
7696 public ArrayInitializer (List<Expression> init, Location loc)
7702 public ArrayInitializer (int count, Location loc)
7703 : this (new List<Expression> (count), loc)
7707 public ArrayInitializer (Location loc)
7715 get { return elements.Count; }
7718 public List<Expression> Elements {
7724 public Expression this [int index] {
7726 return elements [index];
7730 public BlockVariable VariableDeclaration {
7741 public void Add (Expression expr)
7743 elements.Add (expr);
7746 public override bool ContainsEmitWithAwait ()
7748 throw new NotSupportedException ();
7751 public override Expression CreateExpressionTree (ResolveContext ec)
7753 throw new NotSupportedException ("ET");
7756 protected override void CloneTo (CloneContext clonectx, Expression t)
7758 var target = (ArrayInitializer) t;
7760 target.elements = new List<Expression> (elements.Count);
7761 foreach (var element in elements)
7762 target.elements.Add (element.Clone (clonectx));
7765 protected override Expression DoResolve (ResolveContext rc)
7767 var current_field = rc.CurrentMemberDefinition as FieldBase;
7768 TypeExpression type;
7769 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7770 type = new TypeExpression (current_field.MemberType, current_field.Location);
7771 } else if (variable != null) {
7772 if (variable.TypeExpression is VarExpr) {
7773 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7774 return EmptyExpression.Null;
7777 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7779 throw new NotImplementedException ("Unexpected array initializer context");
7782 return new ArrayCreation (type, this).Resolve (rc);
7785 public override void Emit (EmitContext ec)
7787 throw new InternalErrorException ("Missing Resolve call");
7790 public override void FlowAnalysis (FlowAnalysisContext fc)
7792 throw new InternalErrorException ("Missing Resolve call");
7795 public override object Accept (StructuralVisitor visitor)
7797 return visitor.Visit (this);
7802 /// 14.5.10.2: Represents an array creation expression.
7806 /// There are two possible scenarios here: one is an array creation
7807 /// expression that specifies the dimensions and optionally the
7808 /// initialization data and the other which does not need dimensions
7809 /// specified but where initialization data is mandatory.
7811 public class ArrayCreation : Expression
7813 FullNamedExpression requested_base_type;
7814 ArrayInitializer initializers;
7817 // The list of Argument types.
7818 // This is used to construct the `newarray' or constructor signature
7820 protected List<Expression> arguments;
7822 protected TypeSpec array_element_type;
7824 protected int dimensions;
7825 protected readonly ComposedTypeSpecifier rank;
7826 Expression first_emit;
7827 LocalTemporary first_emit_temp;
7829 protected List<Expression> array_data;
7831 Dictionary<int, int> bounds;
7834 // The number of constants in array initializers
7835 int const_initializers_count;
7836 bool only_constant_initializers;
7838 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7839 : this (requested_base_type, rank, initializers, l)
7841 arguments = new List<Expression> (exprs);
7842 num_arguments = arguments.Count;
7846 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7848 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7850 this.requested_base_type = requested_base_type;
7852 this.initializers = initializers;
7856 num_arguments = rank.Dimension;
7860 // For compiler generated single dimensional arrays only
7862 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7863 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7868 // For expressions like int[] foo = { 1, 2, 3 };
7870 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7871 : this (requested_base_type, null, initializers, initializers.Location)
7875 public bool NoEmptyInterpolation { get; set; }
7877 public ComposedTypeSpecifier Rank {
7883 public FullNamedExpression TypeExpression {
7885 return this.requested_base_type;
7889 public ArrayInitializer Initializers {
7891 return this.initializers;
7895 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7897 if (initializers != null && bounds == null) {
7899 // We use this to store all the data values in the order in which we
7900 // will need to store them in the byte blob later
7902 array_data = new List<Expression> (probe.Count);
7903 bounds = new Dictionary<int, int> ();
7906 if (specified_dims) {
7907 Expression a = arguments [idx];
7912 a = ConvertExpressionToArrayIndex (ec, a);
7918 if (initializers != null) {
7919 Constant c = a as Constant;
7920 if (c == null && a is ArrayIndexCast)
7921 c = ((ArrayIndexCast) a).Child as Constant;
7924 ec.Report.Error (150, a.Location, "A constant value is expected");
7930 value = System.Convert.ToInt32 (c.GetValue ());
7932 ec.Report.Error (150, a.Location, "A constant value is expected");
7936 // TODO: probe.Count does not fit ulong in
7937 if (value != probe.Count) {
7938 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7942 bounds[idx] = value;
7946 if (initializers == null)
7949 for (int i = 0; i < probe.Count; ++i) {
7951 if (o is ArrayInitializer) {
7952 var sub_probe = o as ArrayInitializer;
7953 if (idx + 1 >= dimensions){
7954 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7958 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7959 if (!bounds.ContainsKey(idx + 1))
7960 bounds[idx + 1] = sub_probe.Count;
7962 if (bounds[idx + 1] != sub_probe.Count) {
7963 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7967 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7970 } else if (child_bounds > 1) {
7971 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7973 Expression element = ResolveArrayElement (ec, o);
7974 if (element == null)
7977 // Initializers with the default values can be ignored
7978 Constant c = element as Constant;
7980 if (!c.IsDefaultInitializer (array_element_type)) {
7981 ++const_initializers_count;
7984 only_constant_initializers = false;
7987 array_data.Add (element);
7994 public override bool ContainsEmitWithAwait ()
7996 foreach (var arg in arguments) {
7997 if (arg.ContainsEmitWithAwait ())
8001 return InitializersContainAwait ();
8004 public override Expression CreateExpressionTree (ResolveContext ec)
8008 if (array_data == null) {
8009 args = new Arguments (arguments.Count + 1);
8010 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8011 foreach (Expression a in arguments)
8012 args.Add (new Argument (a.CreateExpressionTree (ec)));
8014 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8017 if (dimensions > 1) {
8018 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8022 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8023 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8024 if (array_data != null) {
8025 for (int i = 0; i < array_data.Count; ++i) {
8026 Expression e = array_data [i];
8027 args.Add (new Argument (e.CreateExpressionTree (ec)));
8031 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8034 void UpdateIndices (ResolveContext rc)
8037 for (var probe = initializers; probe != null;) {
8038 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8040 bounds[i++] = probe.Count;
8042 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8043 probe = (ArrayInitializer) probe[0];
8044 } else if (dimensions > i) {
8052 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8054 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8057 public override void FlowAnalysis (FlowAnalysisContext fc)
8059 foreach (var arg in arguments)
8060 arg.FlowAnalysis (fc);
8062 if (array_data != null) {
8063 foreach (var ad in array_data)
8064 ad.FlowAnalysis (fc);
8068 bool InitializersContainAwait ()
8070 if (array_data == null)
8073 foreach (var expr in array_data) {
8074 if (expr.ContainsEmitWithAwait ())
8081 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8083 element = element.Resolve (ec);
8084 if (element == null)
8087 if (element is CompoundAssign.TargetExpression) {
8088 if (first_emit != null)
8089 throw new InternalErrorException ("Can only handle one mutator at a time");
8090 first_emit = element;
8091 element = first_emit_temp = new LocalTemporary (element.Type);
8094 return Convert.ImplicitConversionRequired (
8095 ec, element, array_element_type, loc);
8098 protected bool ResolveInitializers (ResolveContext ec)
8101 only_constant_initializers = true;
8104 if (arguments != null) {
8106 for (int i = 0; i < arguments.Count; ++i) {
8107 res &= CheckIndices (ec, initializers, i, true, dimensions);
8108 if (initializers != null)
8115 arguments = new List<Expression> ();
8117 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8126 // Resolved the type of the array
8128 bool ResolveArrayType (ResolveContext ec)
8133 FullNamedExpression array_type_expr;
8134 if (num_arguments > 0) {
8135 array_type_expr = new ComposedCast (requested_base_type, rank);
8137 array_type_expr = requested_base_type;
8140 type = array_type_expr.ResolveAsType (ec);
8141 if (array_type_expr == null)
8144 var ac = type as ArrayContainer;
8146 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8150 array_element_type = ac.Element;
8151 dimensions = ac.Rank;
8156 protected override Expression DoResolve (ResolveContext ec)
8161 if (!ResolveArrayType (ec))
8165 // validate the initializers and fill in any missing bits
8167 if (!ResolveInitializers (ec))
8170 eclass = ExprClass.Value;
8174 byte [] MakeByteBlob ()
8179 int count = array_data.Count;
8181 TypeSpec element_type = array_element_type;
8182 if (element_type.IsEnum)
8183 element_type = EnumSpec.GetUnderlyingType (element_type);
8185 factor = BuiltinTypeSpec.GetSize (element_type);
8187 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8189 data = new byte [(count * factor + 3) & ~3];
8192 for (int i = 0; i < count; ++i) {
8193 var c = array_data[i] as Constant;
8199 object v = c.GetValue ();
8201 switch (element_type.BuiltinType) {
8202 case BuiltinTypeSpec.Type.Long:
8203 long lval = (long) v;
8205 for (int j = 0; j < factor; ++j) {
8206 data[idx + j] = (byte) (lval & 0xFF);
8210 case BuiltinTypeSpec.Type.ULong:
8211 ulong ulval = (ulong) v;
8213 for (int j = 0; j < factor; ++j) {
8214 data[idx + j] = (byte) (ulval & 0xFF);
8215 ulval = (ulval >> 8);
8218 case BuiltinTypeSpec.Type.Float:
8219 var fval = SingleConverter.SingleToInt32Bits((float) v);
8221 data[idx] = (byte) (fval & 0xff);
8222 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8223 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8224 data[idx + 3] = (byte) (fval >> 24);
8226 case BuiltinTypeSpec.Type.Double:
8227 element = BitConverter.GetBytes ((double) v);
8229 for (int j = 0; j < factor; ++j)
8230 data[idx + j] = element[j];
8232 // FIXME: Handle the ARM float format.
8233 if (!BitConverter.IsLittleEndian)
8234 System.Array.Reverse (data, idx, 8);
8236 case BuiltinTypeSpec.Type.Char:
8237 int chval = (int) ((char) v);
8239 data[idx] = (byte) (chval & 0xff);
8240 data[idx + 1] = (byte) (chval >> 8);
8242 case BuiltinTypeSpec.Type.Short:
8243 int sval = (int) ((short) v);
8245 data[idx] = (byte) (sval & 0xff);
8246 data[idx + 1] = (byte) (sval >> 8);
8248 case BuiltinTypeSpec.Type.UShort:
8249 int usval = (int) ((ushort) v);
8251 data[idx] = (byte) (usval & 0xff);
8252 data[idx + 1] = (byte) (usval >> 8);
8254 case BuiltinTypeSpec.Type.Int:
8257 data[idx] = (byte) (val & 0xff);
8258 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8259 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8260 data[idx + 3] = (byte) (val >> 24);
8262 case BuiltinTypeSpec.Type.UInt:
8263 uint uval = (uint) v;
8265 data[idx] = (byte) (uval & 0xff);
8266 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8267 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8268 data[idx + 3] = (byte) (uval >> 24);
8270 case BuiltinTypeSpec.Type.SByte:
8271 data[idx] = (byte) (sbyte) v;
8273 case BuiltinTypeSpec.Type.Byte:
8274 data[idx] = (byte) v;
8276 case BuiltinTypeSpec.Type.Bool:
8277 data[idx] = (byte) ((bool) v ? 1 : 0);
8279 case BuiltinTypeSpec.Type.Decimal:
8280 int[] bits = Decimal.GetBits ((decimal) v);
8283 // FIXME: For some reason, this doesn't work on the MS runtime.
8284 int[] nbits = new int[4];
8290 for (int j = 0; j < 4; j++) {
8291 data[p++] = (byte) (nbits[j] & 0xff);
8292 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8293 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8294 data[p++] = (byte) (nbits[j] >> 24);
8298 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8307 public override SLE.Expression MakeExpression (BuilderContext ctx)
8310 return base.MakeExpression (ctx);
8312 var initializers = new SLE.Expression [array_data.Count];
8313 for (var i = 0; i < initializers.Length; i++) {
8314 if (array_data [i] == null)
8315 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8317 initializers [i] = array_data [i].MakeExpression (ctx);
8320 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8325 // Emits the initializers for the array
8327 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8329 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8334 // First, the static data
8336 byte [] data = MakeByteBlob ();
8337 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8339 if (stackArray == null) {
8340 ec.Emit (OpCodes.Dup);
8342 stackArray.Emit (ec);
8345 ec.Emit (OpCodes.Ldtoken, fb);
8346 ec.Emit (OpCodes.Call, m);
8351 // Emits pieces of the array that can not be computed at compile
8352 // time (variables and string locations).
8354 // This always expect the top value on the stack to be the array
8356 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8358 int dims = bounds.Count;
8359 var current_pos = new int [dims];
8361 for (int i = 0; i < array_data.Count; i++){
8363 Expression e = array_data [i];
8364 var c = e as Constant;
8366 // Constant can be initialized via StaticInitializer
8367 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8371 if (stackArray != null) {
8372 if (e.ContainsEmitWithAwait ()) {
8373 e = e.EmitToField (ec);
8376 stackArray.EmitLoad (ec);
8378 ec.Emit (OpCodes.Dup);
8381 for (int idx = 0; idx < dims; idx++)
8382 ec.EmitInt (current_pos [idx]);
8385 // If we are dealing with a struct, get the
8386 // address of it, so we can store it.
8388 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8389 ec.Emit (OpCodes.Ldelema, etype);
8393 ec.EmitArrayStore ((ArrayContainer) type);
8399 for (int j = dims - 1; j >= 0; j--){
8401 if (current_pos [j] < bounds [j])
8403 current_pos [j] = 0;
8407 if (stackArray != null)
8408 stackArray.PrepareCleanup (ec);
8411 public override void Emit (EmitContext ec)
8413 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8416 var await_field = EmitToFieldSource (ec);
8417 if (await_field != null)
8418 await_field.Emit (ec);
8421 bool EmitOptimizedEmpty (EmitContext ec)
8423 if (arguments.Count != 1 || dimensions != 1)
8426 var c = arguments [0] as Constant;
8427 if (c == null || !c.IsZeroInteger)
8430 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8431 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8434 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8435 ec.Emit (OpCodes.Call, m);
8439 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8441 if (first_emit != null) {
8442 first_emit.Emit (ec);
8443 first_emit_temp.Store (ec);
8446 StackFieldExpr await_stack_field;
8447 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8448 await_stack_field = ec.GetTemporaryField (type);
8451 await_stack_field = null;
8454 EmitExpressionsList (ec, arguments);
8456 ec.EmitArrayNew ((ArrayContainer) type);
8458 if (initializers == null)
8459 return await_stack_field;
8461 if (await_stack_field != null)
8462 await_stack_field.EmitAssignFromStack (ec);
8466 // Emit static initializer for arrays which contain more than 2 items and
8467 // the static initializer will initialize at least 25% of array values or there
8468 // is more than 10 items to be initialized
8470 // NOTE: const_initializers_count does not contain default constant values.
8472 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8473 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8474 EmitStaticInitializers (ec, await_stack_field);
8476 if (!only_constant_initializers)
8477 EmitDynamicInitializers (ec, false, await_stack_field);
8481 EmitDynamicInitializers (ec, true, await_stack_field);
8484 if (first_emit_temp != null)
8485 first_emit_temp.Release (ec);
8487 return await_stack_field;
8490 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8492 // no multi dimensional or jagged arrays
8493 if (arguments.Count != 1 || array_element_type.IsArray) {
8494 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8498 // No array covariance, except for array -> object
8499 if (type != targetType) {
8500 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8501 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8505 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8506 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8511 // Single dimensional array of 0 size
8512 if (array_data == null) {
8513 IntConstant ic = arguments[0] as IntConstant;
8514 if (ic == null || !ic.IsDefaultValue) {
8515 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8523 enc.Encode (array_data.Count);
8524 foreach (var element in array_data) {
8525 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8529 protected override void CloneTo (CloneContext clonectx, Expression t)
8531 ArrayCreation target = (ArrayCreation) t;
8533 if (requested_base_type != null)
8534 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8536 if (arguments != null){
8537 target.arguments = new List<Expression> (arguments.Count);
8538 foreach (Expression e in arguments)
8539 target.arguments.Add (e.Clone (clonectx));
8542 if (initializers != null)
8543 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8546 public override object Accept (StructuralVisitor visitor)
8548 return visitor.Visit (this);
8553 // Represents an implicitly typed array epxression
8555 class ImplicitlyTypedArrayCreation : ArrayCreation
8557 TypeInferenceContext best_type_inference;
8559 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8560 : base (null, rank, initializers, loc)
8564 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8565 : base (null, initializers, loc)
8569 protected override Expression DoResolve (ResolveContext ec)
8574 dimensions = rank.Dimension;
8576 best_type_inference = new TypeInferenceContext ();
8578 if (!ResolveInitializers (ec))
8581 best_type_inference.FixAllTypes (ec);
8582 array_element_type = best_type_inference.InferredTypeArguments[0];
8583 best_type_inference = null;
8585 if (array_element_type == null ||
8586 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8587 arguments.Count != rank.Dimension) {
8588 ec.Report.Error (826, loc,
8589 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8594 // At this point we found common base type for all initializer elements
8595 // but we have to be sure that all static initializer elements are of
8598 UnifyInitializerElement (ec);
8600 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8601 eclass = ExprClass.Value;
8606 // Converts static initializer only
8608 void UnifyInitializerElement (ResolveContext ec)
8610 for (int i = 0; i < array_data.Count; ++i) {
8611 Expression e = array_data[i];
8613 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8617 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8619 element = element.Resolve (ec);
8620 if (element != null)
8621 best_type_inference.AddCommonTypeBound (element.Type);
8627 sealed class CompilerGeneratedThis : This
8629 public CompilerGeneratedThis (TypeSpec type, Location loc)
8635 protected override Expression DoResolve (ResolveContext rc)
8637 eclass = ExprClass.Variable;
8639 var block = rc.CurrentBlock;
8640 if (block != null) {
8641 var top = block.ParametersBlock.TopBlock;
8642 if (top.ThisVariable != null)
8643 variable_info = top.ThisVariable.VariableInfo;
8650 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8652 return DoResolve (rc);
8655 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8662 /// Represents the `this' construct
8665 public class This : VariableReference
8667 sealed class ThisVariable : ILocalVariable
8669 public static readonly ILocalVariable Instance = new ThisVariable ();
8671 public void Emit (EmitContext ec)
8676 public void EmitAssign (EmitContext ec)
8678 throw new InvalidOperationException ();
8681 public void EmitAddressOf (EmitContext ec)
8687 protected VariableInfo variable_info;
8689 public This (Location loc)
8696 public override string Name {
8697 get { return "this"; }
8700 public override bool IsLockedByStatement {
8708 public override bool IsRef {
8709 get { return type.IsStruct; }
8712 public override bool IsSideEffectFree {
8718 protected override ILocalVariable Variable {
8719 get { return ThisVariable.Instance; }
8722 public override VariableInfo VariableInfo {
8723 get { return variable_info; }
8726 public override bool IsFixed {
8727 get { return false; }
8732 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8735 // It's null for all cases when we don't need to check `this'
8736 // definitive assignment
8738 if (variable_info == null)
8741 if (fc.IsDefinitelyAssigned (variable_info))
8744 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8747 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8749 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8750 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8751 } else if (ec.CurrentAnonymousMethod != null) {
8752 ec.Report.Error (1673, loc,
8753 "Anonymous methods inside structs cannot access instance members of `this'. " +
8754 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8756 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8760 public override void FlowAnalysis (FlowAnalysisContext fc)
8762 CheckStructThisDefiniteAssignment (fc);
8765 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8770 AnonymousMethodStorey storey = ae.Storey;
8771 return storey != null ? storey.HoistedThis : null;
8774 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8776 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8779 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8782 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8788 public virtual void ResolveBase (ResolveContext ec)
8790 eclass = ExprClass.Variable;
8791 type = ec.CurrentType;
8793 if (!IsThisAvailable (ec, false)) {
8794 Error_ThisNotAvailable (ec);
8798 var block = ec.CurrentBlock;
8799 if (block != null) {
8800 var top = block.ParametersBlock.TopBlock;
8801 if (top.ThisVariable != null)
8802 variable_info = top.ThisVariable.VariableInfo;
8804 AnonymousExpression am = ec.CurrentAnonymousMethod;
8805 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8807 // Hoisted this is almost like hoisted variable but not exactly. When
8808 // there is no variable hoisted we can simply emit an instance method
8809 // without lifting this into a storey. Unfotunatelly this complicates
8810 // things in other cases because we don't know where this will be hoisted
8811 // until top-level block is fully resolved
8813 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8814 am.SetHasThisAccess ();
8819 protected override Expression DoResolve (ResolveContext ec)
8825 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8827 if (eclass == ExprClass.Unresolved)
8831 if (right_side == EmptyExpression.UnaryAddress)
8832 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8833 else if (right_side == EmptyExpression.OutAccess)
8834 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8836 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8842 public override int GetHashCode()
8844 throw new NotImplementedException ();
8847 public override bool Equals (object obj)
8849 This t = obj as This;
8856 protected override void CloneTo (CloneContext clonectx, Expression t)
8861 public override void SetHasAddressTaken ()
8866 public override object Accept (StructuralVisitor visitor)
8868 return visitor.Visit (this);
8873 /// Represents the `__arglist' construct
8875 public class ArglistAccess : Expression
8877 public ArglistAccess (Location loc)
8882 protected override void CloneTo (CloneContext clonectx, Expression target)
8887 public override bool ContainsEmitWithAwait ()
8892 public override Expression CreateExpressionTree (ResolveContext ec)
8894 throw new NotSupportedException ("ET");
8897 protected override Expression DoResolve (ResolveContext ec)
8899 eclass = ExprClass.Variable;
8900 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8902 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8903 ec.Report.Error (190, loc,
8904 "The __arglist construct is valid only within a variable argument method");
8910 public override void Emit (EmitContext ec)
8912 ec.Emit (OpCodes.Arglist);
8915 public override object Accept (StructuralVisitor visitor)
8917 return visitor.Visit (this);
8922 /// Represents the `__arglist (....)' construct
8924 public class Arglist : Expression
8926 Arguments arguments;
8928 public Arglist (Location loc)
8933 public Arglist (Arguments args, Location l)
8939 public Arguments Arguments {
8945 public MetaType[] ArgumentTypes {
8947 if (arguments == null)
8948 return MetaType.EmptyTypes;
8950 var retval = new MetaType[arguments.Count];
8951 for (int i = 0; i < retval.Length; i++)
8952 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8958 public override bool ContainsEmitWithAwait ()
8960 throw new NotImplementedException ();
8963 public override Expression CreateExpressionTree (ResolveContext ec)
8965 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8969 protected override Expression DoResolve (ResolveContext ec)
8971 eclass = ExprClass.Variable;
8972 type = InternalType.Arglist;
8973 if (arguments != null) {
8974 bool dynamic; // Can be ignored as there is always only 1 overload
8975 arguments.Resolve (ec, out dynamic);
8981 public override void Emit (EmitContext ec)
8983 if (arguments != null)
8984 arguments.Emit (ec);
8987 protected override void CloneTo (CloneContext clonectx, Expression t)
8989 Arglist target = (Arglist) t;
8991 if (arguments != null)
8992 target.arguments = arguments.Clone (clonectx);
8995 public override object Accept (StructuralVisitor visitor)
8997 return visitor.Visit (this);
9001 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9003 FullNamedExpression texpr;
9005 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9012 public FullNamedExpression TypeExpression {
9018 public override bool ContainsEmitWithAwait ()
9023 public void AddressOf (EmitContext ec, AddressOp mode)
9026 ec.Emit (OpCodes.Refanyval, type);
9029 protected override Expression DoResolve (ResolveContext rc)
9031 expr = expr.Resolve (rc);
9032 type = texpr.ResolveAsType (rc);
9033 if (expr == null || type == null)
9036 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9037 eclass = ExprClass.Variable;
9041 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9043 return DoResolve (rc);
9046 public override void Emit (EmitContext ec)
9049 ec.Emit (OpCodes.Refanyval, type);
9050 ec.EmitLoadFromPtr (type);
9053 public void Emit (EmitContext ec, bool leave_copy)
9055 throw new NotImplementedException ();
9058 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9061 ec.Emit (OpCodes.Refanyval, type);
9064 LocalTemporary temporary = null;
9066 ec.Emit (OpCodes.Dup);
9067 temporary = new LocalTemporary (source.Type);
9068 temporary.Store (ec);
9071 ec.EmitStoreFromPtr (type);
9073 if (temporary != null) {
9074 temporary.Emit (ec);
9075 temporary.Release (ec);
9079 public override object Accept (StructuralVisitor visitor)
9081 return visitor.Visit (this);
9085 public class RefTypeExpr : ShimExpression
9087 public RefTypeExpr (Expression expr, Location loc)
9093 protected override Expression DoResolve (ResolveContext rc)
9095 expr = expr.Resolve (rc);
9099 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9103 type = rc.BuiltinTypes.Type;
9104 eclass = ExprClass.Value;
9108 public override void Emit (EmitContext ec)
9111 ec.Emit (OpCodes.Refanytype);
9112 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9114 ec.Emit (OpCodes.Call, m);
9117 public override object Accept (StructuralVisitor visitor)
9119 return visitor.Visit (this);
9123 public class MakeRefExpr : ShimExpression
9125 public MakeRefExpr (Expression expr, Location loc)
9131 public override bool ContainsEmitWithAwait ()
9133 throw new NotImplementedException ();
9136 protected override Expression DoResolve (ResolveContext rc)
9138 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9139 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9140 eclass = ExprClass.Value;
9144 public override void Emit (EmitContext ec)
9146 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9147 ec.Emit (OpCodes.Mkrefany, expr.Type);
9150 public override object Accept (StructuralVisitor visitor)
9152 return visitor.Visit (this);
9157 /// Implements the typeof operator
9159 public class TypeOf : Expression {
9160 FullNamedExpression QueriedType;
9163 public TypeOf (FullNamedExpression queried_type, Location l)
9165 QueriedType = queried_type;
9170 // Use this constructor for any compiler generated typeof expression
9172 public TypeOf (TypeSpec type, Location loc)
9174 this.typearg = type;
9180 public override bool IsSideEffectFree {
9186 public TypeSpec TypeArgument {
9192 public FullNamedExpression TypeExpression {
9201 protected override void CloneTo (CloneContext clonectx, Expression t)
9203 TypeOf target = (TypeOf) t;
9204 if (QueriedType != null)
9205 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9208 public override bool ContainsEmitWithAwait ()
9213 public override Expression CreateExpressionTree (ResolveContext ec)
9215 Arguments args = new Arguments (2);
9216 args.Add (new Argument (this));
9217 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9218 return CreateExpressionFactoryCall (ec, "Constant", args);
9221 protected override Expression DoResolve (ResolveContext ec)
9223 if (eclass != ExprClass.Unresolved)
9226 if (typearg == null) {
9228 // Pointer types are allowed without explicit unsafe, they are just tokens
9230 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9231 typearg = QueriedType.ResolveAsType (ec, true);
9234 if (typearg == null)
9237 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9238 ec.Report.Error (1962, QueriedType.Location,
9239 "The typeof operator cannot be used on the dynamic type");
9243 type = ec.BuiltinTypes.Type;
9245 // Even though what is returned is a type object, it's treated as a value by the compiler.
9246 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9247 eclass = ExprClass.Value;
9251 static bool ContainsDynamicType (TypeSpec type)
9253 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9256 var element_container = type as ElementTypeSpec;
9257 if (element_container != null)
9258 return ContainsDynamicType (element_container.Element);
9260 foreach (var t in type.TypeArguments) {
9261 if (ContainsDynamicType (t)) {
9269 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9271 // Target type is not System.Type therefore must be object
9272 // and we need to use different encoding sequence
9273 if (targetType != type)
9276 if (typearg is InflatedTypeSpec) {
9279 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9280 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9281 typearg.GetSignatureForError ());
9285 gt = gt.DeclaringType;
9286 } while (gt != null);
9289 if (ContainsDynamicType (typearg)) {
9290 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9294 enc.EncodeTypeName (typearg);
9297 public override void Emit (EmitContext ec)
9299 ec.Emit (OpCodes.Ldtoken, typearg);
9300 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9302 ec.Emit (OpCodes.Call, m);
9305 public override object Accept (StructuralVisitor visitor)
9307 return visitor.Visit (this);
9311 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9313 public TypeOfMethod (MethodSpec method, Location loc)
9314 : base (method, loc)
9318 protected override Expression DoResolve (ResolveContext ec)
9320 if (member.IsConstructor) {
9321 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9323 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9329 return base.DoResolve (ec);
9332 public override void Emit (EmitContext ec)
9334 ec.Emit (OpCodes.Ldtoken, member);
9337 ec.Emit (OpCodes.Castclass, type);
9340 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9342 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9345 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9347 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9351 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9353 protected readonly T member;
9355 protected TypeOfMember (T member, Location loc)
9357 this.member = member;
9361 public override bool IsSideEffectFree {
9367 public override bool ContainsEmitWithAwait ()
9372 public override Expression CreateExpressionTree (ResolveContext ec)
9374 Arguments args = new Arguments (2);
9375 args.Add (new Argument (this));
9376 args.Add (new Argument (new TypeOf (type, loc)));
9377 return CreateExpressionFactoryCall (ec, "Constant", args);
9380 protected override Expression DoResolve (ResolveContext ec)
9382 eclass = ExprClass.Value;
9386 public override void Emit (EmitContext ec)
9388 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9389 PredefinedMember<MethodSpec> p;
9391 p = GetTypeFromHandleGeneric (ec);
9392 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9394 p = GetTypeFromHandle (ec);
9397 var mi = p.Resolve (loc);
9399 ec.Emit (OpCodes.Call, mi);
9402 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9403 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9406 sealed class TypeOfField : TypeOfMember<FieldSpec>
9408 public TypeOfField (FieldSpec field, Location loc)
9413 protected override Expression DoResolve (ResolveContext ec)
9415 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9419 return base.DoResolve (ec);
9422 public override void Emit (EmitContext ec)
9424 ec.Emit (OpCodes.Ldtoken, member);
9428 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9430 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9433 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9435 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9440 /// Implements the sizeof expression
9442 public class SizeOf : Expression {
9443 readonly Expression texpr;
9444 TypeSpec type_queried;
9446 public SizeOf (Expression queried_type, Location l)
9448 this.texpr = queried_type;
9452 public override bool IsSideEffectFree {
9458 public Expression TypeExpression {
9464 public override bool ContainsEmitWithAwait ()
9469 public override Expression CreateExpressionTree (ResolveContext ec)
9471 Error_PointerInsideExpressionTree (ec);
9475 protected override Expression DoResolve (ResolveContext ec)
9477 type_queried = texpr.ResolveAsType (ec);
9478 if (type_queried == null)
9481 if (type_queried.IsEnum)
9482 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9484 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9486 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9489 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9494 ec.Report.Error (233, loc,
9495 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9496 type_queried.GetSignatureForError ());
9499 type = ec.BuiltinTypes.Int;
9500 eclass = ExprClass.Value;
9504 public override void Emit (EmitContext ec)
9506 ec.Emit (OpCodes.Sizeof, type_queried);
9509 protected override void CloneTo (CloneContext clonectx, Expression t)
9513 public override object Accept (StructuralVisitor visitor)
9515 return visitor.Visit (this);
9520 /// Implements the qualified-alias-member (::) expression.
9522 public class QualifiedAliasMember : MemberAccess
9524 readonly string alias;
9525 public static readonly string GlobalAlias = "global";
9527 public QualifiedAliasMember (string alias, string identifier, Location l)
9528 : base (null, identifier, l)
9533 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9534 : base (null, identifier, targs, l)
9539 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9540 : base (null, identifier, arity, l)
9545 public string Alias {
9551 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9553 if (alias == GlobalAlias)
9554 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9556 int errors = mc.Module.Compiler.Report.Errors;
9557 var expr = mc.LookupNamespaceAlias (alias);
9559 if (errors == mc.Module.Compiler.Report.Errors)
9560 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9568 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9570 expr = CreateExpressionFromAlias (mc);
9574 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9577 protected override Expression DoResolve (ResolveContext rc)
9579 return ResolveAsTypeOrNamespace (rc, false);
9582 public override string GetSignatureForError ()
9585 if (targs != null) {
9586 name = Name + "<" + targs.GetSignatureForError () + ">";
9589 return alias + "::" + name;
9592 public override bool HasConditionalAccess ()
9597 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9599 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9600 rc.Module.Compiler.Report.Error (687, loc,
9601 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9602 GetSignatureForError ());
9607 return DoResolve (rc);
9610 protected override void CloneTo (CloneContext clonectx, Expression t)
9615 public override object Accept (StructuralVisitor visitor)
9617 return visitor.Visit (this);
9622 /// Implements the member access expression
9624 public class MemberAccess : ATypeNameExpression
9626 protected Expression expr;
9628 public MemberAccess (Expression expr, string id)
9629 : base (id, expr.Location)
9634 public MemberAccess (Expression expr, string identifier, Location loc)
9635 : base (identifier, loc)
9640 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9641 : base (identifier, args, loc)
9646 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9647 : base (identifier, arity, loc)
9652 public Expression LeftExpression {
9658 public override Location StartLocation {
9660 return expr == null ? loc : expr.StartLocation;
9664 protected override Expression DoResolve (ResolveContext rc)
9666 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9668 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9673 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9675 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9677 if (e is TypeExpr) {
9678 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9683 e = e.ResolveLValue (rc, rhs);
9688 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9690 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9691 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9693 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9696 public override bool HasConditionalAccess ()
9698 return LeftExpression.HasConditionalAccess ();
9701 public static bool IsValidDotExpression (TypeSpec type)
9703 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9704 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9706 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9709 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9711 var sn = expr as SimpleName;
9712 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9715 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9718 // Resolve expression which does have type set as we need expression type
9719 // with disable flow analysis as we don't know whether left side expression
9720 // is used as variable or type
9722 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9723 expr = expr.Resolve (rc);
9724 } else if (expr is TypeParameterExpr) {
9725 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9729 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9730 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9731 expr = expr.Resolve (rc, flags);
9734 expr = expr.Resolve (rc, flags);
9741 var ns = expr as NamespaceExpression;
9743 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9745 if (retval == null) {
9746 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9751 if (HasTypeArguments)
9752 return new GenericTypeExpr (retval.Type, targs, loc);
9754 targs.Resolve (rc, false);
9760 var cma = this as ConditionalMemberAccess;
9763 TypeSpec expr_type = expr.Type;
9764 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9765 me = expr as MemberExpr;
9767 me.ResolveInstanceExpression (rc, null);
9769 Arguments args = new Arguments (1);
9770 args.Add (new Argument (expr));
9773 return new DynamicConditionalMemberBinder (Name, args, loc);
9775 return new DynamicMemberBinder (Name, args, loc);
9779 if (!IsNullPropagatingValid (expr.Type)) {
9780 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9784 if (expr_type.IsNullableType) {
9785 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9786 expr_type = expr.Type;
9790 if (!IsValidDotExpression (expr_type)) {
9791 Error_OperatorCannotBeApplied (rc, expr_type);
9795 var lookup_arity = Arity;
9796 bool errorMode = false;
9797 Expression member_lookup;
9799 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9800 if (member_lookup == null) {
9802 // Try to look for extension method when member lookup failed
9804 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9805 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9806 if (methods != null) {
9807 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9808 if (HasTypeArguments) {
9809 if (!targs.Resolve (rc, false))
9812 emg.SetTypeArguments (rc, targs);
9816 emg.ConditionalAccess = true;
9818 // TODO: it should really skip the checks bellow
9819 return emg.Resolve (rc);
9825 if (member_lookup == null) {
9826 var dep = expr_type.GetMissingDependencies ();
9828 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9829 } else if (expr is TypeExpr) {
9830 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9832 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9838 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9839 // Leave it to overload resolution to report correct error
9840 } else if (!(member_lookup is TypeExpr)) {
9841 // TODO: rc.SymbolRelatedToPreviousError
9842 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9847 if (member_lookup != null)
9851 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9855 TypeExpr texpr = member_lookup as TypeExpr;
9856 if (texpr != null) {
9857 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9858 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9859 Name, texpr.GetSignatureForError ());
9862 if (!texpr.Type.IsAccessible (rc)) {
9863 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9864 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9868 if (HasTypeArguments) {
9869 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9872 return member_lookup;
9875 me = member_lookup as MemberExpr;
9877 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9882 me.ConditionalAccess = true;
9885 me = me.ResolveMemberAccess (rc, expr, sn);
9888 if (!targs.Resolve (rc, false))
9891 me.SetTypeArguments (rc, targs);
9897 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9899 FullNamedExpression fexpr = expr as FullNamedExpression;
9900 if (fexpr == null) {
9901 expr.ResolveAsType (rc);
9905 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9907 if (expr_resolved == null)
9910 var ns = expr_resolved as NamespaceExpression;
9912 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9914 if (retval == null) {
9915 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9916 } else if (Arity > 0) {
9917 if (HasTypeArguments) {
9918 retval = new GenericTypeExpr (retval.Type, targs, loc);
9919 if (retval.ResolveAsType (rc) == null)
9922 targs.Resolve (rc, allowUnboundTypeArguments);
9924 retval = new GenericOpenTypeExpr (retval.Type, loc);
9931 var tnew_expr = expr_resolved.ResolveAsType (rc);
9932 if (tnew_expr == null)
9935 TypeSpec expr_type = tnew_expr;
9936 if (TypeManager.IsGenericParameter (expr_type)) {
9937 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9938 tnew_expr.GetSignatureForError ());
9942 var qam = this as QualifiedAliasMember;
9944 rc.Module.Compiler.Report.Error (431, loc,
9945 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9950 TypeSpec nested = null;
9951 while (expr_type != null) {
9952 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9953 if (nested == null) {
9954 if (expr_type == tnew_expr) {
9955 Error_IdentifierNotFound (rc, expr_type);
9959 expr_type = tnew_expr;
9960 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9961 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9965 if (nested.IsAccessible (rc))
9969 // Keep looking after inaccessible candidate but only if
9970 // we are not in same context as the definition itself
9972 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9975 expr_type = expr_type.BaseType;
9980 if (HasTypeArguments) {
9981 texpr = new GenericTypeExpr (nested, targs, loc);
9983 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9985 texpr = new GenericOpenTypeExpr (nested, loc);
9987 } else if (expr_resolved is GenericOpenTypeExpr) {
9988 texpr = new GenericOpenTypeExpr (nested, loc);
9990 texpr = new TypeExpression (nested, loc);
9993 if (texpr.ResolveAsType (rc) == null)
9999 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10001 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
10003 if (nested != null) {
10004 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10008 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10009 if (any_other_member != null) {
10010 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10014 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10015 Name, expr_type.GetSignatureForError ());
10018 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10020 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10023 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10025 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10026 ec.Report.SymbolRelatedToPreviousError (type);
10028 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10030 // a using directive or an assembly reference
10031 if (cand != null) {
10032 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10034 missing = "an assembly reference";
10037 ec.Report.Error (1061, loc,
10038 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10039 type.GetSignatureForError (), name, missing);
10043 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10046 public override string GetSignatureForError ()
10048 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10051 protected override void CloneTo (CloneContext clonectx, Expression t)
10053 MemberAccess target = (MemberAccess) t;
10055 target.expr = expr.Clone (clonectx);
10058 public override object Accept (StructuralVisitor visitor)
10060 return visitor.Visit (this);
10064 public class ConditionalMemberAccess : MemberAccess
10066 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10067 : base (expr, identifier, args, loc)
10071 public override bool HasConditionalAccess ()
10078 /// Implements checked expressions
10080 public class CheckedExpr : Expression {
10082 public Expression Expr;
10084 public CheckedExpr (Expression e, Location l)
10090 public override bool ContainsEmitWithAwait ()
10092 return Expr.ContainsEmitWithAwait ();
10095 public override Expression CreateExpressionTree (ResolveContext ec)
10097 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10098 return Expr.CreateExpressionTree (ec);
10101 protected override Expression DoResolve (ResolveContext ec)
10103 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10104 Expr = Expr.Resolve (ec);
10109 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10112 eclass = Expr.eclass;
10117 public override void Emit (EmitContext ec)
10119 using (ec.With (EmitContext.Options.CheckedScope, true))
10123 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10125 using (ec.With (EmitContext.Options.CheckedScope, true))
10126 Expr.EmitBranchable (ec, target, on_true);
10129 public override void FlowAnalysis (FlowAnalysisContext fc)
10131 Expr.FlowAnalysis (fc);
10134 public override SLE.Expression MakeExpression (BuilderContext ctx)
10136 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10137 return Expr.MakeExpression (ctx);
10141 protected override void CloneTo (CloneContext clonectx, Expression t)
10143 CheckedExpr target = (CheckedExpr) t;
10145 target.Expr = Expr.Clone (clonectx);
10148 public override object Accept (StructuralVisitor visitor)
10150 return visitor.Visit (this);
10155 /// Implements the unchecked expression
10157 public class UnCheckedExpr : Expression {
10159 public Expression Expr;
10161 public UnCheckedExpr (Expression e, Location l)
10167 public override bool ContainsEmitWithAwait ()
10169 return Expr.ContainsEmitWithAwait ();
10172 public override Expression CreateExpressionTree (ResolveContext ec)
10174 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10175 return Expr.CreateExpressionTree (ec);
10178 protected override Expression DoResolve (ResolveContext ec)
10180 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10181 Expr = Expr.Resolve (ec);
10186 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10189 eclass = Expr.eclass;
10194 public override void Emit (EmitContext ec)
10196 using (ec.With (EmitContext.Options.CheckedScope, false))
10200 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10202 using (ec.With (EmitContext.Options.CheckedScope, false))
10203 Expr.EmitBranchable (ec, target, on_true);
10206 public override void FlowAnalysis (FlowAnalysisContext fc)
10208 Expr.FlowAnalysis (fc);
10211 protected override void CloneTo (CloneContext clonectx, Expression t)
10213 UnCheckedExpr target = (UnCheckedExpr) t;
10215 target.Expr = Expr.Clone (clonectx);
10218 public override object Accept (StructuralVisitor visitor)
10220 return visitor.Visit (this);
10225 /// An Element Access expression.
10227 /// During semantic analysis these are transformed into
10228 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10230 public class ElementAccess : Expression
10232 public Arguments Arguments;
10233 public Expression Expr;
10234 bool conditional_access_receiver;
10236 public ElementAccess (Expression e, Arguments args, Location loc)
10240 this.Arguments = args;
10243 public bool ConditionalAccess { get; set; }
10245 public override Location StartLocation {
10247 return Expr.StartLocation;
10251 public override bool ContainsEmitWithAwait ()
10253 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10257 // We perform some simple tests, and then to "split" the emit and store
10258 // code we create an instance of a different class, and return that.
10260 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10262 if (conditionalAccessReceiver)
10263 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10265 Expr = Expr.Resolve (ec);
10267 if (conditionalAccessReceiver)
10268 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10275 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10276 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10280 if (type.IsArray) {
10281 var aa = new ArrayAccess (this, loc) {
10282 ConditionalAccess = ConditionalAccess,
10285 if (conditionalAccessReceiver)
10286 aa.SetConditionalAccessReceiver ();
10291 if (type.IsPointer)
10292 return Expr.MakePointerAccess (ec, type, Arguments);
10294 FieldExpr fe = Expr as FieldExpr;
10296 var ff = fe.Spec as FixedFieldSpec;
10298 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10302 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10303 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10304 var indexer = new IndexerExpr (indexers, type, this) {
10305 ConditionalAccess = ConditionalAccess
10308 if (conditionalAccessReceiver)
10309 indexer.SetConditionalAccessReceiver ();
10314 Error_CannotApplyIndexing (ec, type, loc);
10319 public override Expression CreateExpressionTree (ResolveContext ec)
10321 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10322 Expr.CreateExpressionTree (ec));
10324 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10327 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10329 if (type != InternalType.ErrorType) {
10330 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10331 type.GetSignatureForError ());
10335 public override bool HasConditionalAccess ()
10337 return ConditionalAccess || Expr.HasConditionalAccess ();
10340 void ResolveConditionalAccessReceiver (ResolveContext rc)
10342 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10343 conditional_access_receiver = true;
10347 protected override Expression DoResolve (ResolveContext rc)
10349 ResolveConditionalAccessReceiver (rc);
10351 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10355 return expr.Resolve (rc);
10358 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10360 var res = CreateAccessExpression (ec, false);
10364 return res.ResolveLValue (ec, rhs);
10367 public override void Emit (EmitContext ec)
10369 throw new Exception ("Should never be reached");
10372 public override void FlowAnalysis (FlowAnalysisContext fc)
10374 Expr.FlowAnalysis (fc);
10376 Arguments.FlowAnalysis (fc);
10379 public override string GetSignatureForError ()
10381 return Expr.GetSignatureForError ();
10384 protected override void CloneTo (CloneContext clonectx, Expression t)
10386 ElementAccess target = (ElementAccess) t;
10388 target.Expr = Expr.Clone (clonectx);
10389 if (Arguments != null)
10390 target.Arguments = Arguments.Clone (clonectx);
10393 public override object Accept (StructuralVisitor visitor)
10395 return visitor.Visit (this);
10400 /// Implements array access
10402 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10404 // Points to our "data" repository
10408 LocalTemporary temp;
10410 bool? has_await_args;
10411 bool conditional_access_receiver;
10413 public ArrayAccess (ElementAccess ea_data, Location l)
10419 public bool ConditionalAccess { get; set; }
10421 public void AddressOf (EmitContext ec, AddressOp mode)
10423 var ac = (ArrayContainer) ea.Expr.Type;
10425 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10426 LoadInstanceAndArguments (ec, false, true);
10429 LoadInstanceAndArguments (ec, false, false);
10431 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10432 ec.Emit (OpCodes.Readonly);
10434 ec.EmitArrayAddress (ac);
10437 public override Expression CreateExpressionTree (ResolveContext ec)
10439 if (ConditionalAccess)
10440 Error_NullShortCircuitInsideExpressionTree (ec);
10442 return ea.CreateExpressionTree (ec);
10445 public override bool ContainsEmitWithAwait ()
10447 return ea.ContainsEmitWithAwait ();
10450 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10452 if (HasConditionalAccess ())
10453 Error_NullPropagatingLValue (ec);
10455 return DoResolve (ec);
10458 protected override Expression DoResolve (ResolveContext ec)
10460 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10462 ea.Arguments.Resolve (ec, out dynamic);
10464 var ac = ea.Expr.Type as ArrayContainer;
10465 int rank = ea.Arguments.Count;
10466 if (ac.Rank != rank) {
10467 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10468 rank.ToString (), ac.Rank.ToString ());
10473 if (type.IsPointer && !ec.IsUnsafe) {
10474 UnsafeError (ec, ea.Location);
10477 if (conditional_access_receiver)
10478 type = LiftMemberType (ec, type);
10480 foreach (Argument a in ea.Arguments) {
10481 var na = a as NamedArgument;
10483 ElementAccess.Error_NamedArgument (na, ec.Report);
10485 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10488 eclass = ExprClass.Variable;
10493 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10495 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10498 public override void FlowAnalysis (FlowAnalysisContext fc)
10500 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10502 ea.FlowAnalysis (fc);
10504 if (conditional_access_receiver)
10505 fc.DefiniteAssignment = da;
10508 public override bool HasConditionalAccess ()
10510 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10514 // Load the array arguments into the stack.
10516 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10518 if (prepareAwait) {
10519 ea.Expr = ea.Expr.EmitToField (ec);
10521 var ie = new InstanceEmitter (ea.Expr, false);
10522 ie.Emit (ec, ConditionalAccess);
10524 if (duplicateArguments) {
10525 ec.Emit (OpCodes.Dup);
10527 var copy = new LocalTemporary (ea.Expr.Type);
10533 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10534 if (dup_args != null)
10535 ea.Arguments = dup_args;
10538 public void Emit (EmitContext ec, bool leave_copy)
10541 ec.EmitLoadFromPtr (type);
10543 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10544 LoadInstanceAndArguments (ec, false, true);
10547 if (conditional_access_receiver)
10548 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10550 var ac = (ArrayContainer) ea.Expr.Type;
10551 LoadInstanceAndArguments (ec, false, false);
10552 ec.EmitArrayLoad (ac);
10554 if (conditional_access_receiver)
10555 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10559 ec.Emit (OpCodes.Dup);
10560 temp = new LocalTemporary (this.type);
10565 public override void Emit (EmitContext ec)
10570 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10572 var ac = (ArrayContainer) ea.Expr.Type;
10573 TypeSpec t = source.Type;
10575 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10578 // When we are dealing with a struct, get the address of it to avoid value copy
10579 // Same cannot be done for reference type because array covariance and the
10580 // check in ldelema requires to specify the type of array element stored at the index
10582 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10583 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10585 if (has_await_args.Value) {
10586 if (source.ContainsEmitWithAwait ()) {
10587 source = source.EmitToField (ec);
10588 isCompound = false;
10592 LoadInstanceAndArguments (ec, isCompound, false);
10597 ec.EmitArrayAddress (ac);
10600 ec.Emit (OpCodes.Dup);
10604 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10606 if (has_await_args.Value) {
10607 if (source.ContainsEmitWithAwait ())
10608 source = source.EmitToField (ec);
10610 LoadInstanceAndArguments (ec, false, false);
10617 var lt = ea.Expr as LocalTemporary;
10623 ec.Emit (OpCodes.Dup);
10624 temp = new LocalTemporary (this.type);
10629 ec.EmitStoreFromPtr (t);
10631 ec.EmitArrayStore (ac);
10634 if (temp != null) {
10640 public override Expression EmitToField (EmitContext ec)
10643 // Have to be specialized for arrays to get access to
10644 // underlying element. Instead of another result copy we
10645 // need direct access to element
10649 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10651 ea.Expr = ea.Expr.EmitToField (ec);
10652 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10656 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10658 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10661 public override SLE.Expression MakeExpression (BuilderContext ctx)
10663 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10666 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10668 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10669 return Arguments.MakeExpression (ea.Arguments, ctx);
10673 public void SetConditionalAccessReceiver ()
10675 conditional_access_receiver = true;
10680 // Indexer access expression
10682 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10684 IList<MemberSpec> indexers;
10685 Arguments arguments;
10686 TypeSpec queried_type;
10688 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10689 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10693 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10696 this.indexers = indexers;
10697 this.queried_type = queriedType;
10698 this.InstanceExpression = instance;
10699 this.arguments = args;
10704 protected override Arguments Arguments {
10713 protected override TypeSpec DeclaringType {
10715 return best_candidate.DeclaringType;
10719 public override bool IsInstance {
10725 public override bool IsStatic {
10731 public override string KindName {
10732 get { return "indexer"; }
10735 public override string Name {
10743 public override bool ContainsEmitWithAwait ()
10745 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10748 public override Expression CreateExpressionTree (ResolveContext ec)
10750 if (ConditionalAccess) {
10751 Error_NullShortCircuitInsideExpressionTree (ec);
10754 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10755 InstanceExpression.CreateExpressionTree (ec),
10756 new TypeOfMethod (Getter, loc));
10758 return CreateExpressionFactoryCall (ec, "Call", args);
10761 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10763 LocalTemporary await_source_arg = null;
10766 emitting_compound_assignment = true;
10767 if (source is DynamicExpressionStatement) {
10772 emitting_compound_assignment = false;
10774 if (has_await_arguments) {
10775 await_source_arg = new LocalTemporary (Type);
10776 await_source_arg.Store (ec);
10778 arguments.Add (new Argument (await_source_arg));
10781 temp = await_source_arg;
10784 has_await_arguments = false;
10789 ec.Emit (OpCodes.Dup);
10790 temp = new LocalTemporary (Type);
10796 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10797 source = source.EmitToField (ec);
10799 temp = new LocalTemporary (Type);
10806 arguments.Add (new Argument (source));
10809 var call = new CallEmitter ();
10810 call.InstanceExpression = InstanceExpression;
10811 if (arguments == null)
10812 call.InstanceExpressionOnStack = true;
10814 call.Emit (ec, Setter, arguments, loc);
10816 if (temp != null) {
10819 } else if (leave_copy) {
10823 if (await_source_arg != null) {
10824 await_source_arg.Release (ec);
10828 public override void FlowAnalysis (FlowAnalysisContext fc)
10830 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10832 base.FlowAnalysis (fc);
10833 arguments.FlowAnalysis (fc);
10835 if (conditional_access_receiver)
10836 fc.DefiniteAssignment = da;
10839 public override string GetSignatureForError ()
10841 return best_candidate.GetSignatureForError ();
10844 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10847 throw new NotSupportedException ();
10849 var value = new[] { source.MakeExpression (ctx) };
10850 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10851 return SLE.Expression.Block (
10852 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10857 public override SLE.Expression MakeExpression (BuilderContext ctx)
10860 return base.MakeExpression (ctx);
10862 var args = Arguments.MakeExpression (arguments, ctx);
10863 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10867 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10869 if (best_candidate != null)
10872 eclass = ExprClass.IndexerAccess;
10875 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10876 arguments.Resolve (rc, out dynamic);
10879 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10882 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10883 res.BaseMembersProvider = this;
10884 res.InstanceQualifier = this;
10886 // TODO: Do I need 2 argument sets?
10887 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10888 if (best_candidate != null)
10889 type = res.BestCandidateReturnType;
10890 else if (!res.BestCandidateIsDynamic)
10895 // It has dynamic arguments
10898 Arguments args = new Arguments (arguments.Count + 1);
10900 rc.Report.Error (1972, loc,
10901 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10903 args.Add (new Argument (InstanceExpression));
10905 args.AddRange (arguments);
10907 best_candidate = null;
10908 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10912 // Try to avoid resolving left expression again
10914 if (right_side != null)
10915 ResolveInstanceExpression (rc, right_side);
10920 protected override void CloneTo (CloneContext clonectx, Expression t)
10922 IndexerExpr target = (IndexerExpr) t;
10924 if (arguments != null)
10925 target.arguments = arguments.Clone (clonectx);
10928 public void SetConditionalAccessReceiver ()
10930 conditional_access_receiver = true;
10933 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10935 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10938 #region IBaseMembersProvider Members
10940 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10942 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10945 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10947 if (queried_type == member.DeclaringType)
10950 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10951 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10954 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10963 // A base access expression
10965 public class BaseThis : This
10967 public BaseThis (Location loc)
10972 public BaseThis (TypeSpec type, Location loc)
10976 eclass = ExprClass.Variable;
10981 public override string Name {
10989 public override Expression CreateExpressionTree (ResolveContext ec)
10991 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10992 return base.CreateExpressionTree (ec);
10995 public override void Emit (EmitContext ec)
10999 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11000 var context_type = ec.CurrentType;
11001 ec.Emit (OpCodes.Ldobj, context_type);
11002 ec.Emit (OpCodes.Box, context_type);
11006 protected override void Error_ThisNotAvailable (ResolveContext ec)
11009 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11011 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11015 public override void ResolveBase (ResolveContext ec)
11017 base.ResolveBase (ec);
11018 type = ec.CurrentType.BaseType;
11021 public override object Accept (StructuralVisitor visitor)
11023 return visitor.Visit (this);
11028 /// This class exists solely to pass the Type around and to be a dummy
11029 /// that can be passed to the conversion functions (this is used by
11030 /// foreach implementation to typecast the object return value from
11031 /// get_Current into the proper type. All code has been generated and
11032 /// we only care about the side effect conversions to be performed
11034 /// This is also now used as a placeholder where a no-action expression
11035 /// is needed (the `New' class).
11037 public class EmptyExpression : Expression
11039 sealed class OutAccessExpression : EmptyExpression
11041 public OutAccessExpression (TypeSpec t)
11046 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11048 rc.Report.Error (206, right_side.Location,
11049 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11055 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11056 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11057 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11058 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11059 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11060 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11061 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11062 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11064 public EmptyExpression (TypeSpec t)
11067 eclass = ExprClass.Value;
11068 loc = Location.Null;
11071 protected override void CloneTo (CloneContext clonectx, Expression target)
11075 public override bool ContainsEmitWithAwait ()
11080 public override Expression CreateExpressionTree (ResolveContext ec)
11082 throw new NotSupportedException ("ET");
11085 protected override Expression DoResolve (ResolveContext ec)
11090 public override void Emit (EmitContext ec)
11092 // nothing, as we only exist to not do anything.
11095 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11099 public override void EmitSideEffect (EmitContext ec)
11103 public override object Accept (StructuralVisitor visitor)
11105 return visitor.Visit (this);
11109 sealed class EmptyAwaitExpression : EmptyExpression
11111 public EmptyAwaitExpression (TypeSpec type)
11116 public override bool ContainsEmitWithAwait ()
11123 // Empty statement expression
11125 public sealed class EmptyExpressionStatement : ExpressionStatement
11127 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11129 private EmptyExpressionStatement ()
11131 loc = Location.Null;
11134 public override bool ContainsEmitWithAwait ()
11139 public override Expression CreateExpressionTree (ResolveContext ec)
11144 public override void EmitStatement (EmitContext ec)
11149 protected override Expression DoResolve (ResolveContext ec)
11151 eclass = ExprClass.Value;
11152 type = ec.BuiltinTypes.Object;
11156 public override void Emit (EmitContext ec)
11161 public override object Accept (StructuralVisitor visitor)
11163 return visitor.Visit (this);
11167 public class ErrorExpression : EmptyExpression
11169 public static readonly ErrorExpression Instance = new ErrorExpression ();
11171 private ErrorExpression ()
11172 : base (InternalType.ErrorType)
11176 public override Expression CreateExpressionTree (ResolveContext ec)
11181 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11186 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11190 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11194 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11198 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11202 public override object Accept (StructuralVisitor visitor)
11204 return visitor.Visit (this);
11208 public class UserCast : Expression {
11212 public UserCast (MethodSpec method, Expression source, Location l)
11214 if (source == null)
11215 throw new ArgumentNullException ("source");
11217 this.method = method;
11218 this.source = source;
11219 type = method.ReturnType;
11223 public Expression Source {
11232 public override bool ContainsEmitWithAwait ()
11234 return source.ContainsEmitWithAwait ();
11237 public override Expression CreateExpressionTree (ResolveContext ec)
11239 Arguments args = new Arguments (3);
11240 args.Add (new Argument (source.CreateExpressionTree (ec)));
11241 args.Add (new Argument (new TypeOf (type, loc)));
11242 args.Add (new Argument (new TypeOfMethod (method, loc)));
11243 return CreateExpressionFactoryCall (ec, "Convert", args);
11246 protected override Expression DoResolve (ResolveContext ec)
11248 method.CheckObsoleteness (ec, source.Location);
11250 eclass = ExprClass.Value;
11254 public override void Emit (EmitContext ec)
11257 ec.MarkCallEntry (loc);
11258 ec.Emit (OpCodes.Call, method);
11261 public override void FlowAnalysis (FlowAnalysisContext fc)
11263 source.FlowAnalysis (fc);
11266 public override string GetSignatureForError ()
11268 return TypeManager.CSharpSignature (method);
11271 public override SLE.Expression MakeExpression (BuilderContext ctx)
11274 return base.MakeExpression (ctx);
11276 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11282 // Holds additional type specifiers like ?, *, []
11284 public class ComposedTypeSpecifier
11286 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11288 public readonly int Dimension;
11289 public readonly Location Location;
11291 public ComposedTypeSpecifier (int specifier, Location loc)
11293 this.Dimension = specifier;
11294 this.Location = loc;
11298 public bool IsNullable {
11300 return Dimension == -1;
11304 public bool IsPointer {
11306 return Dimension == -2;
11310 public ComposedTypeSpecifier Next { get; set; }
11314 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11316 return new ComposedTypeSpecifier (dimension, loc);
11319 public static ComposedTypeSpecifier CreateNullable (Location loc)
11321 return new ComposedTypeSpecifier (-1, loc);
11324 public static ComposedTypeSpecifier CreatePointer (Location loc)
11326 return new ComposedTypeSpecifier (-2, loc);
11329 public string GetSignatureForError ()
11334 ArrayContainer.GetPostfixSignature (Dimension);
11336 return Next != null ? s + Next.GetSignatureForError () : s;
11341 // This class is used to "construct" the type during a typecast
11342 // operation. Since the Type.GetType class in .NET can parse
11343 // the type specification, we just use this to construct the type
11344 // one bit at a time.
11346 public class ComposedCast : TypeExpr {
11347 FullNamedExpression left;
11348 ComposedTypeSpecifier spec;
11350 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11353 throw new ArgumentNullException ("spec");
11357 this.loc = left.Location;
11360 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11362 type = left.ResolveAsType (ec);
11366 eclass = ExprClass.Type;
11368 var single_spec = spec;
11370 if (single_spec.IsNullable) {
11371 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11375 single_spec = single_spec.Next;
11376 } else if (single_spec.IsPointer) {
11378 // Declared fields cannot have unmanaged check done before all types are defined
11380 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11383 if (!ec.IsUnsafe) {
11384 UnsafeError (ec.Module.Compiler.Report, loc);
11388 type = PointerContainer.MakeType (ec.Module, type);
11389 single_spec = single_spec.Next;
11390 } while (single_spec != null && single_spec.IsPointer);
11393 if (single_spec != null && single_spec.Dimension > 0) {
11394 if (type.IsSpecialRuntimeType) {
11395 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11396 } else if (type.IsStatic) {
11397 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11398 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11399 type.GetSignatureForError ());
11401 MakeArray (ec.Module, single_spec);
11408 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11410 if (spec.Next != null)
11411 MakeArray (module, spec.Next);
11413 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11416 public override string GetSignatureForError ()
11418 return left.GetSignatureForError () + spec.GetSignatureForError ();
11421 public override object Accept (StructuralVisitor visitor)
11423 return visitor.Visit (this);
11427 class FixedBufferPtr : Expression
11429 readonly Expression array;
11431 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11433 this.type = array_type;
11434 this.array = array;
11438 public override bool ContainsEmitWithAwait ()
11440 throw new NotImplementedException ();
11443 public override Expression CreateExpressionTree (ResolveContext ec)
11445 Error_PointerInsideExpressionTree (ec);
11449 public override void Emit(EmitContext ec)
11454 protected override Expression DoResolve (ResolveContext ec)
11456 type = PointerContainer.MakeType (ec.Module, type);
11457 eclass = ExprClass.Value;
11464 // This class is used to represent the address of an array, used
11465 // only by the Fixed statement, this generates "&a [0]" construct
11466 // for fixed (char *pa = a)
11468 class ArrayPtr : FixedBufferPtr
11470 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11471 base (array, array_type, l)
11475 public override void Emit (EmitContext ec)
11480 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11485 // Encapsulates a conversion rules required for array indexes
11487 public class ArrayIndexCast : TypeCast
11489 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11490 : base (expr, returnType)
11492 if (expr.Type == returnType) // int -> int
11493 throw new ArgumentException ("unnecessary array index conversion");
11496 public override Expression CreateExpressionTree (ResolveContext ec)
11498 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11499 return base.CreateExpressionTree (ec);
11503 public override void Emit (EmitContext ec)
11507 switch (child.Type.BuiltinType) {
11508 case BuiltinTypeSpec.Type.UInt:
11509 ec.Emit (OpCodes.Conv_U);
11511 case BuiltinTypeSpec.Type.Long:
11512 ec.Emit (OpCodes.Conv_Ovf_I);
11514 case BuiltinTypeSpec.Type.ULong:
11515 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11518 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11524 // Implements the `stackalloc' keyword
11526 public class StackAlloc : Expression {
11531 public StackAlloc (Expression type, Expression count, Location l)
11534 this.count = count;
11538 public Expression TypeExpression {
11544 public Expression CountExpression {
11550 public override bool ContainsEmitWithAwait ()
11555 public override Expression CreateExpressionTree (ResolveContext ec)
11557 throw new NotSupportedException ("ET");
11560 protected override Expression DoResolve (ResolveContext ec)
11562 count = count.Resolve (ec);
11566 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11567 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11572 Constant c = count as Constant;
11573 if (c != null && c.IsNegative) {
11574 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11577 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11578 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11581 otype = texpr.ResolveAsType (ec);
11585 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11588 type = PointerContainer.MakeType (ec.Module, otype);
11589 eclass = ExprClass.Value;
11594 public override void Emit (EmitContext ec)
11596 int size = BuiltinTypeSpec.GetSize (otype);
11601 ec.Emit (OpCodes.Sizeof, otype);
11605 ec.Emit (OpCodes.Mul_Ovf_Un);
11606 ec.Emit (OpCodes.Localloc);
11609 protected override void CloneTo (CloneContext clonectx, Expression t)
11611 StackAlloc target = (StackAlloc) t;
11612 target.count = count.Clone (clonectx);
11613 target.texpr = texpr.Clone (clonectx);
11616 public override object Accept (StructuralVisitor visitor)
11618 return visitor.Visit (this);
11623 // An object initializer expression
11625 public class ElementInitializer : Assign
11627 public readonly string Name;
11629 public ElementInitializer (string name, Expression initializer, Location loc)
11630 : base (null, initializer, loc)
11635 public bool IsDictionaryInitializer {
11637 return Name == null;
11641 protected override void CloneTo (CloneContext clonectx, Expression t)
11643 ElementInitializer target = (ElementInitializer) t;
11644 target.source = source.Clone (clonectx);
11647 public override Expression CreateExpressionTree (ResolveContext ec)
11649 Arguments args = new Arguments (2);
11650 FieldExpr fe = target as FieldExpr;
11652 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11654 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11657 Expression arg_expr;
11658 var cinit = source as CollectionOrObjectInitializers;
11659 if (cinit == null) {
11661 arg_expr = source.CreateExpressionTree (ec);
11663 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11664 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11667 args.Add (new Argument (arg_expr));
11668 return CreateExpressionFactoryCall (ec, mname, args);
11671 protected override Expression DoResolve (ResolveContext ec)
11673 if (source == null)
11674 return EmptyExpressionStatement.Instance;
11676 if (!ResolveElement (ec))
11679 if (source is CollectionOrObjectInitializers) {
11680 target = target.Resolve (ec);
11681 if (target == null)
11684 Expression previous = ec.CurrentInitializerVariable;
11685 ec.CurrentInitializerVariable = target;
11686 source = source.Resolve (ec);
11687 ec.CurrentInitializerVariable = previous;
11688 if (source == null)
11691 eclass = source.eclass;
11692 type = source.Type;
11697 return base.DoResolve (ec);
11700 public override void EmitStatement (EmitContext ec)
11702 if (source is CollectionOrObjectInitializers)
11705 base.EmitStatement (ec);
11708 protected virtual bool ResolveElement (ResolveContext rc)
11710 var t = rc.CurrentInitializerVariable.Type;
11711 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11712 Arguments args = new Arguments (1);
11713 args.Add (new Argument (rc.CurrentInitializerVariable));
11714 target = new DynamicMemberBinder (Name, args, loc);
11716 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11717 if (member == null) {
11718 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11720 if (member != null) {
11721 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11722 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11727 if (member == null) {
11728 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11732 var me = member as MemberExpr;
11733 if (me is EventExpr) {
11734 me = me.ResolveMemberAccess (rc, null, null);
11735 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11736 rc.Report.Error (1913, loc,
11737 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11738 member.GetSignatureForError ());
11744 rc.Report.Error (1914, loc,
11745 "Static field or property `{0}' cannot be assigned in an object initializer",
11746 me.GetSignatureForError ());
11750 me.InstanceExpression = rc.CurrentInitializerVariable;
11758 // A collection initializer expression
11760 class CollectionElementInitializer : Invocation
11762 public class ElementInitializerArgument : Argument
11764 public ElementInitializerArgument (Expression e)
11770 sealed class AddMemberAccess : MemberAccess
11772 public AddMemberAccess (Expression expr, Location loc)
11773 : base (expr, "Add", loc)
11777 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11779 if (TypeManager.HasElementType (type))
11782 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11786 public CollectionElementInitializer (Expression argument)
11787 : base (null, new Arguments (1))
11789 base.arguments.Add (new ElementInitializerArgument (argument));
11790 this.loc = argument.Location;
11793 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11794 : base (null, new Arguments (arguments.Count))
11796 foreach (Expression e in arguments)
11797 base.arguments.Add (new ElementInitializerArgument (e));
11802 public CollectionElementInitializer (Location loc)
11803 : base (null, null)
11808 public override Expression CreateExpressionTree (ResolveContext ec)
11810 Arguments args = new Arguments (2);
11811 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11813 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11814 foreach (Argument a in arguments) {
11815 if (a.ArgType == Argument.AType.ExtensionType) {
11816 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11819 expr_initializers.Add (a.CreateExpressionTree (ec));
11822 args.Add (new Argument (new ArrayCreation (
11823 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11824 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11827 protected override void CloneTo (CloneContext clonectx, Expression t)
11829 CollectionElementInitializer target = (CollectionElementInitializer) t;
11830 if (arguments != null)
11831 target.arguments = arguments.Clone (clonectx);
11834 protected override Expression DoResolve (ResolveContext ec)
11836 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11838 return base.DoResolve (ec);
11842 class DictionaryElementInitializer : ElementInitializer
11844 readonly Arguments args;
11846 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11847 : base (null, initializer, loc)
11849 this.args = arguments;
11852 public override Expression CreateExpressionTree (ResolveContext ec)
11854 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11858 protected override bool ResolveElement (ResolveContext rc)
11860 var init = rc.CurrentInitializerVariable;
11861 var type = init.Type;
11863 if (type.IsArray) {
11864 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11868 if (type.IsPointer) {
11869 target = init.MakePointerAccess (rc, type, args);
11873 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11874 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11875 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11879 target = new IndexerExpr (indexers, type, init, args, loc);
11885 // A block of object or collection initializers
11887 public class CollectionOrObjectInitializers : ExpressionStatement
11889 IList<Expression> initializers;
11890 bool is_collection_initialization;
11892 public CollectionOrObjectInitializers (Location loc)
11893 : this (new Expression[0], loc)
11897 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11899 this.initializers = initializers;
11903 public IList<Expression> Initializers {
11905 return initializers;
11909 public bool IsEmpty {
11911 return initializers.Count == 0;
11915 public bool IsCollectionInitializer {
11917 return is_collection_initialization;
11921 protected override void CloneTo (CloneContext clonectx, Expression target)
11923 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11925 t.initializers = new List<Expression> (initializers.Count);
11926 foreach (var e in initializers)
11927 t.initializers.Add (e.Clone (clonectx));
11930 public override bool ContainsEmitWithAwait ()
11932 foreach (var e in initializers) {
11933 if (e.ContainsEmitWithAwait ())
11940 public override Expression CreateExpressionTree (ResolveContext ec)
11942 return CreateExpressionTree (ec, false);
11945 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11947 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11948 foreach (Expression e in initializers) {
11949 Expression expr = e.CreateExpressionTree (ec);
11951 expr_initializers.Add (expr);
11955 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11957 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11960 protected override Expression DoResolve (ResolveContext ec)
11962 List<string> element_names = null;
11963 for (int i = 0; i < initializers.Count; ++i) {
11964 Expression initializer = initializers [i];
11965 ElementInitializer element_initializer = initializer as ElementInitializer;
11968 if (element_initializer != null) {
11969 element_names = new List<string> (initializers.Count);
11970 if (!element_initializer.IsDictionaryInitializer)
11971 element_names.Add (element_initializer.Name);
11972 } else if (initializer is CompletingExpression) {
11973 initializer.Resolve (ec);
11974 throw new InternalErrorException ("This line should never be reached");
11976 var t = ec.CurrentInitializerVariable.Type;
11977 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11978 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11979 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11980 "object initializer because type `{1}' does not implement `{2}' interface",
11981 ec.CurrentInitializerVariable.GetSignatureForError (),
11982 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11983 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11986 is_collection_initialization = true;
11989 if (is_collection_initialization != (element_initializer == null)) {
11990 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11991 is_collection_initialization ? "collection initializer" : "object initializer");
11995 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11996 if (element_names.Contains (element_initializer.Name)) {
11997 ec.Report.Error (1912, element_initializer.Location,
11998 "An object initializer includes more than one member `{0}' initialization",
11999 element_initializer.Name);
12001 element_names.Add (element_initializer.Name);
12006 Expression e = initializer.Resolve (ec);
12007 if (e == EmptyExpressionStatement.Instance)
12008 initializers.RemoveAt (i--);
12010 initializers [i] = e;
12013 type = ec.CurrentInitializerVariable.Type;
12014 if (is_collection_initialization) {
12015 if (TypeManager.HasElementType (type)) {
12016 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12017 type.GetSignatureForError ());
12021 eclass = ExprClass.Variable;
12025 public override void Emit (EmitContext ec)
12027 EmitStatement (ec);
12030 public override void EmitStatement (EmitContext ec)
12032 foreach (ExpressionStatement e in initializers) {
12033 // TODO: need location region
12034 ec.Mark (e.Location);
12035 e.EmitStatement (ec);
12039 public override void FlowAnalysis (FlowAnalysisContext fc)
12041 foreach (var initializer in initializers) {
12042 if (initializer != null)
12043 initializer.FlowAnalysis (fc);
12049 // New expression with element/object initializers
12051 public class NewInitialize : New
12054 // This class serves as a proxy for variable initializer target instances.
12055 // A real variable is assigned later when we resolve left side of an
12058 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12060 NewInitialize new_instance;
12062 public InitializerTargetExpression (NewInitialize newInstance)
12064 this.type = newInstance.type;
12065 this.loc = newInstance.loc;
12066 this.eclass = newInstance.eclass;
12067 this.new_instance = newInstance;
12070 public override bool ContainsEmitWithAwait ()
12075 public override Expression CreateExpressionTree (ResolveContext ec)
12077 // Should not be reached
12078 throw new NotSupportedException ("ET");
12081 protected override Expression DoResolve (ResolveContext ec)
12086 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12091 public override void Emit (EmitContext ec)
12093 Expression e = (Expression) new_instance.instance;
12097 public override Expression EmitToField (EmitContext ec)
12099 return (Expression) new_instance.instance;
12102 #region IMemoryLocation Members
12104 public void AddressOf (EmitContext ec, AddressOp mode)
12106 new_instance.instance.AddressOf (ec, mode);
12112 CollectionOrObjectInitializers initializers;
12113 IMemoryLocation instance;
12114 DynamicExpressionStatement dynamic;
12116 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12117 : base (requested_type, arguments, l)
12119 this.initializers = initializers;
12122 public CollectionOrObjectInitializers Initializers {
12124 return initializers;
12128 protected override void CloneTo (CloneContext clonectx, Expression t)
12130 base.CloneTo (clonectx, t);
12132 NewInitialize target = (NewInitialize) t;
12133 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12136 public override bool ContainsEmitWithAwait ()
12138 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12141 public override Expression CreateExpressionTree (ResolveContext ec)
12143 Arguments args = new Arguments (2);
12144 args.Add (new Argument (base.CreateExpressionTree (ec)));
12145 if (!initializers.IsEmpty)
12146 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12148 return CreateExpressionFactoryCall (ec,
12149 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12153 protected override Expression DoResolve (ResolveContext ec)
12155 Expression e = base.DoResolve (ec);
12159 if (type.IsDelegate) {
12160 ec.Report.Error (1958, Initializers.Location,
12161 "Object and collection initializers cannot be used to instantiate a delegate");
12164 Expression previous = ec.CurrentInitializerVariable;
12165 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12166 initializers.Resolve (ec);
12167 ec.CurrentInitializerVariable = previous;
12169 dynamic = e as DynamicExpressionStatement;
12170 if (dynamic != null)
12176 public override void Emit (EmitContext ec)
12178 if (!CanEmitOptimizedLocalTarget (ec)) {
12179 var fe = ec.GetTemporaryField (type);
12181 if (!Emit (ec, fe))
12190 public override bool Emit (EmitContext ec, IMemoryLocation target)
12193 // Expression is initialized into temporary target then moved
12194 // to real one for atomicity
12196 IMemoryLocation temp_target = target;
12198 LocalTemporary temp = null;
12199 bool by_ref = false;
12200 if (!initializers.IsEmpty) {
12201 temp_target = target as LocalTemporary;
12202 if (temp_target == null)
12203 temp_target = target as StackFieldExpr;
12205 if (temp_target == null) {
12206 var vr = target as VariableReference;
12207 if (vr != null && vr.IsRef) {
12213 if (temp_target == null)
12214 temp_target = temp = new LocalTemporary (type);
12217 bool left_on_stack;
12218 if (dynamic != null) {
12220 left_on_stack = true;
12222 left_on_stack = base.Emit (ec, temp_target);
12225 if (initializers.IsEmpty)
12226 return left_on_stack;
12228 StackFieldExpr sf = null;
12230 // Move a new instance (reference-type) to local temporary variable
12231 if (left_on_stack) {
12233 temp_target = temp = new LocalTemporary (type);
12239 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12241 throw new NotImplementedException ();
12243 sf = ec.GetTemporaryField (type);
12244 sf.EmitAssign (ec, temp, false, false);
12247 left_on_stack = false;
12251 instance = temp_target;
12253 initializers.Emit (ec);
12255 ((Expression)temp_target).Emit (ec);
12261 sf.IsAvailableForReuse = true;
12266 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12268 return !(method == null && TypeSpec.IsValueType (type) &&
12269 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12270 initializers.ContainsEmitWithAwait ());
12273 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12275 instance = base.EmitAddressOf (ec, Mode);
12277 if (!initializers.IsEmpty)
12278 initializers.Emit (ec);
12283 public override void FlowAnalysis (FlowAnalysisContext fc)
12285 base.FlowAnalysis (fc);
12286 initializers.FlowAnalysis (fc);
12289 public override object Accept (StructuralVisitor visitor)
12291 return visitor.Visit (this);
12295 public class NewAnonymousType : New
12297 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12299 List<AnonymousTypeParameter> parameters;
12300 readonly TypeContainer parent;
12301 AnonymousTypeClass anonymous_type;
12303 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12304 : base (null, null, loc)
12306 this.parameters = parameters;
12307 this.parent = parent;
12310 public List<AnonymousTypeParameter> Parameters {
12312 return this.parameters;
12316 protected override void CloneTo (CloneContext clonectx, Expression target)
12318 if (parameters == null)
12321 NewAnonymousType t = (NewAnonymousType) target;
12322 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12323 foreach (AnonymousTypeParameter atp in parameters)
12324 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12327 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12329 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12333 type = AnonymousTypeClass.Create (parent, parameters, loc);
12337 int errors = ec.Report.Errors;
12338 type.CreateContainer ();
12339 type.DefineContainer ();
12341 if ((ec.Report.Errors - errors) == 0) {
12342 parent.Module.AddAnonymousType (type);
12343 type.PrepareEmit ();
12349 public override Expression CreateExpressionTree (ResolveContext ec)
12351 if (parameters == null)
12352 return base.CreateExpressionTree (ec);
12354 var init = new ArrayInitializer (parameters.Count, loc);
12355 foreach (var m in anonymous_type.Members) {
12356 var p = m as Property;
12358 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12361 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12362 foreach (Argument a in arguments)
12363 ctor_args.Add (a.CreateExpressionTree (ec));
12365 Arguments args = new Arguments (3);
12366 args.Add (new Argument (new TypeOfMethod (method, loc)));
12367 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12368 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12370 return CreateExpressionFactoryCall (ec, "New", args);
12373 protected override Expression DoResolve (ResolveContext ec)
12375 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12376 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12380 if (parameters == null) {
12381 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12382 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12383 return base.DoResolve (ec);
12386 bool error = false;
12387 arguments = new Arguments (parameters.Count);
12388 var t_args = new TypeSpec [parameters.Count];
12389 for (int i = 0; i < parameters.Count; ++i) {
12390 Expression e = parameters [i].Resolve (ec);
12396 arguments.Add (new Argument (e));
12397 t_args [i] = e.Type;
12403 anonymous_type = CreateAnonymousType (ec, parameters);
12404 if (anonymous_type == null)
12407 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12408 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12409 eclass = ExprClass.Value;
12413 public override object Accept (StructuralVisitor visitor)
12415 return visitor.Visit (this);
12419 public class AnonymousTypeParameter : ShimExpression
12421 public readonly string Name;
12423 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12424 : base (initializer)
12430 public AnonymousTypeParameter (Parameter parameter)
12431 : base (new SimpleName (parameter.Name, parameter.Location))
12433 this.Name = parameter.Name;
12434 this.loc = parameter.Location;
12437 public override bool Equals (object o)
12439 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12440 return other != null && Name == other.Name;
12443 public override int GetHashCode ()
12445 return Name.GetHashCode ();
12448 protected override Expression DoResolve (ResolveContext ec)
12450 Expression e = expr.Resolve (ec);
12454 if (e.eclass == ExprClass.MethodGroup) {
12455 Error_InvalidInitializer (ec, e.ExprClassName);
12460 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12461 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12468 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12470 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12471 Name, initializer);
12475 public class CatchFilterExpression : BooleanExpression
12477 public CatchFilterExpression (Expression expr, Location loc)
12484 public class InterpolatedString : Expression
12486 readonly StringLiteral start, end;
12487 List<Expression> interpolations;
12488 Arguments arguments;
12490 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12492 this.start = start;
12494 this.interpolations = interpolations;
12495 loc = start.Location;
12498 protected override void CloneTo (CloneContext clonectx, Expression t)
12500 InterpolatedString target = (InterpolatedString) t;
12502 if (interpolations != null) {
12503 target.interpolations = new List<Expression> ();
12504 foreach (var interpolation in interpolations) {
12505 target.interpolations.Add (interpolation.Clone (clonectx));
12510 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12512 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12513 if (factory == null)
12516 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12517 var res = new Invocation (ma, arguments).Resolve (rc);
12518 if (res != null && res.Type != type)
12519 res = Convert.ExplicitConversion (rc, res, type, loc);
12524 public override bool ContainsEmitWithAwait ()
12526 if (interpolations == null)
12529 foreach (var expr in interpolations) {
12530 if (expr.ContainsEmitWithAwait ())
12537 public override Expression CreateExpressionTree (ResolveContext rc)
12539 var best = ResolveBestFormatOverload (rc);
12543 Expression instance = new NullLiteral (loc);
12544 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12545 return CreateExpressionFactoryCall (rc, "Call", args);
12548 protected override Expression DoResolve (ResolveContext rc)
12552 if (interpolations == null) {
12554 arguments = new Arguments (1);
12556 arguments = new Arguments (interpolations.Count);
12558 var sb = new StringBuilder (start.Value);
12559 for (int i = 0; i < interpolations.Count; ++i) {
12561 sb.Append ('{').Append (i / 2);
12562 var isi = (InterpolatedStringInsert)interpolations [i];
12563 if (isi.Alignment != null) {
12565 var value = isi.ResolveAligment (rc);
12567 sb.Append (value.Value);
12570 if (isi.Format != null) {
12572 sb.Append (isi.Format);
12576 arguments.Add (new Argument (isi.Resolve (rc)));
12578 sb.Append (((StringLiteral)interpolations [i]).Value);
12582 sb.Append (end.Value);
12583 str = sb.ToString ();
12586 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12588 eclass = ExprClass.Value;
12589 type = rc.BuiltinTypes.String;
12593 public override void Emit (EmitContext ec)
12595 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12596 if (interpolations == null) {
12597 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12598 if (str != start.Value)
12599 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12606 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12610 var ca = new CallEmitter ();
12611 ca.Emit (ec, best, arguments, loc);
12614 public override void FlowAnalysis (FlowAnalysisContext fc)
12616 if (interpolations != null) {
12617 foreach (var expr in interpolations) {
12618 expr.FlowAnalysis (fc);
12623 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12625 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12626 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12627 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12631 public class InterpolatedStringInsert : CompositeExpression
12633 public InterpolatedStringInsert (Expression expr)
12638 public Expression Alignment { get; set; }
12639 public string Format { get; set; }
12641 protected override void CloneTo (CloneContext clonectx, Expression t)
12643 var target = (InterpolatedStringInsert)t;
12644 target.expr = expr.Clone (clonectx);
12645 if (Alignment != null)
12646 target.Alignment = Alignment.Clone (clonectx);
12649 protected override Expression DoResolve (ResolveContext rc)
12651 var expr = base.DoResolve (rc);
12656 // For better error reporting, assumes the built-in implementation uses object
12659 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12662 public override void FlowAnalysis (FlowAnalysisContext fc)
12664 Child.FlowAnalysis (fc);
12667 public int? ResolveAligment (ResolveContext rc)
12669 var c = Alignment.ResolveLabelConstant (rc);
12673 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12677 var value = (int) c.GetValueAsLong ();
12678 if (value > 32767 || value < -32767) {
12679 rc.Report.Warning (8094, 1, Alignment.Location,
12680 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");