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;
2366 type = InternalType.ErrorType;
2370 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2371 if (TypeManager.IsGenericParameter (type)) {
2372 ec.Report.Error (413, loc,
2373 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2374 probe_type_expr.GetSignatureForError ());
2376 ec.Report.Error (77, loc,
2377 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2378 type.GetSignatureForError ());
2383 if (expr.IsNull && type.IsNullableType) {
2384 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2387 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2388 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2392 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2394 e = EmptyCast.Create (e, type);
2395 return ReducedExpression.Create (e, this).Resolve (ec);
2398 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2399 if (TypeManager.IsGenericParameter (etype))
2400 expr = new BoxedCast (expr, etype);
2405 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2406 expr = new BoxedCast (expr, etype);
2410 if (etype != InternalType.ErrorType) {
2411 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2412 etype.GetSignatureForError (), type.GetSignatureForError ());
2418 public override object Accept (StructuralVisitor visitor)
2420 return visitor.Visit (this);
2425 // This represents a typecast in the source language.
2427 public class Cast : ShimExpression {
2428 Expression target_type;
2430 public Cast (Expression cast_type, Expression expr, Location loc)
2433 this.target_type = cast_type;
2437 public Expression TargetType {
2438 get { return target_type; }
2441 protected override Expression DoResolve (ResolveContext ec)
2443 expr = expr.Resolve (ec);
2447 type = target_type.ResolveAsType (ec);
2451 if (type.IsStatic) {
2452 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2456 if (type.IsPointer && !ec.IsUnsafe) {
2457 UnsafeError (ec, loc);
2460 eclass = ExprClass.Value;
2462 Constant c = expr as Constant;
2464 c = c.Reduce (ec, type);
2469 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2471 return EmptyCast.Create (res, type);
2476 protected override void CloneTo (CloneContext clonectx, Expression t)
2478 Cast target = (Cast) t;
2480 target.target_type = target_type.Clone (clonectx);
2481 target.expr = expr.Clone (clonectx);
2484 public override object Accept (StructuralVisitor visitor)
2486 return visitor.Visit (this);
2490 public class ImplicitCast : ShimExpression
2494 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2497 this.loc = expr.Location;
2499 this.arrayAccess = arrayAccess;
2502 protected override Expression DoResolve (ResolveContext ec)
2504 expr = expr.Resolve (ec);
2509 expr = ConvertExpressionToArrayIndex (ec, expr);
2511 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2517 public class DeclarationExpression : Expression, IMemoryLocation
2519 LocalVariableReference lvr;
2521 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2523 VariableType = variableType;
2524 Variable = variable;
2525 this.loc = variable.Location;
2528 public LocalVariable Variable { get; set; }
2529 public Expression Initializer { get; set; }
2530 public FullNamedExpression VariableType { get; set; }
2532 public void AddressOf (EmitContext ec, AddressOp mode)
2534 Variable.CreateBuilder (ec);
2536 if (Initializer != null) {
2537 lvr.EmitAssign (ec, Initializer, false, false);
2540 lvr.AddressOf (ec, mode);
2543 protected override void CloneTo (CloneContext clonectx, Expression t)
2545 var target = (DeclarationExpression) t;
2547 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2549 if (Initializer != null)
2550 target.Initializer = Initializer.Clone (clonectx);
2553 public override Expression CreateExpressionTree (ResolveContext rc)
2555 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2559 bool DoResolveCommon (ResolveContext rc)
2561 var var_expr = VariableType as VarExpr;
2562 if (var_expr != null) {
2563 type = InternalType.VarOutType;
2565 type = VariableType.ResolveAsType (rc);
2570 if (Initializer != null) {
2571 Initializer = Initializer.Resolve (rc);
2573 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2574 type = var_expr.Type;
2578 Variable.Type = type;
2579 lvr = new LocalVariableReference (Variable, loc);
2581 eclass = ExprClass.Variable;
2585 protected override Expression DoResolve (ResolveContext rc)
2587 if (DoResolveCommon (rc))
2593 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2595 if (lvr == null && DoResolveCommon (rc))
2596 lvr.ResolveLValue (rc, right_side);
2601 public override void Emit (EmitContext ec)
2603 throw new NotImplementedException ();
2608 // C# 2.0 Default value expression
2610 public class DefaultValueExpression : Expression
2614 public DefaultValueExpression (Expression expr, Location loc)
2620 public Expression Expr {
2626 public override bool IsSideEffectFree {
2632 public override bool ContainsEmitWithAwait ()
2637 public override Expression CreateExpressionTree (ResolveContext ec)
2639 Arguments args = new Arguments (2);
2640 args.Add (new Argument (this));
2641 args.Add (new Argument (new TypeOf (type, loc)));
2642 return CreateExpressionFactoryCall (ec, "Constant", args);
2645 protected override Expression DoResolve (ResolveContext ec)
2647 type = expr.ResolveAsType (ec);
2651 if (type.IsStatic) {
2652 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2656 return new NullLiteral (Location).ConvertImplicitly (type);
2658 if (TypeSpec.IsReferenceType (type))
2659 return new NullConstant (type, loc);
2661 Constant c = New.Constantify (type, expr.Location);
2665 eclass = ExprClass.Variable;
2669 public override void Emit (EmitContext ec)
2671 LocalTemporary temp_storage = new LocalTemporary(type);
2673 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2674 ec.Emit(OpCodes.Initobj, type);
2675 temp_storage.Emit(ec);
2676 temp_storage.Release (ec);
2680 public override SLE.Expression MakeExpression (BuilderContext ctx)
2682 return SLE.Expression.Default (type.GetMetaInfo ());
2686 protected override void CloneTo (CloneContext clonectx, Expression t)
2688 DefaultValueExpression target = (DefaultValueExpression) t;
2690 target.expr = expr.Clone (clonectx);
2693 public override object Accept (StructuralVisitor visitor)
2695 return visitor.Visit (this);
2700 /// Binary operators
2702 public class Binary : Expression, IDynamicBinder
2704 public class PredefinedOperator
2706 protected readonly TypeSpec left;
2707 protected readonly TypeSpec right;
2708 protected readonly TypeSpec left_unwrap;
2709 protected readonly TypeSpec right_unwrap;
2710 public readonly Operator OperatorsMask;
2711 public TypeSpec ReturnType;
2713 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2714 : this (ltype, rtype, op_mask, ltype)
2718 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2719 : this (type, type, op_mask, return_type)
2723 public PredefinedOperator (TypeSpec type, Operator op_mask)
2724 : this (type, type, op_mask, type)
2728 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2730 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2731 throw new InternalErrorException ("Only masked values can be used");
2733 if ((op_mask & Operator.NullableMask) != 0) {
2734 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2735 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2737 left_unwrap = ltype;
2738 right_unwrap = rtype;
2743 this.OperatorsMask = op_mask;
2744 this.ReturnType = return_type;
2747 public bool IsLifted {
2749 return (OperatorsMask & Operator.NullableMask) != 0;
2753 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2757 var left_expr = b.left;
2758 var right_expr = b.right;
2760 b.type = ReturnType;
2763 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2764 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2765 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2768 if (right_expr.IsNull) {
2769 if ((b.oper & Operator.EqualityMask) != 0) {
2770 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2771 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2772 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2773 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2774 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2776 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2777 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2779 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2780 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2782 return b.CreateLiftedValueTypeResult (rc, left);
2784 } else if (left_expr.IsNull) {
2785 if ((b.oper & Operator.EqualityMask) != 0) {
2786 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2787 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2788 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2789 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2790 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2792 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2793 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2795 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2796 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2798 return b.CreateLiftedValueTypeResult (rc, right);
2804 // A user operators does not support multiple user conversions, but decimal type
2805 // is considered to be predefined type therefore we apply predefined operators rules
2806 // and then look for decimal user-operator implementation
2808 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2809 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2810 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2812 return b.ResolveUserOperator (rc, b.left, b.right);
2815 c = right_expr as Constant;
2817 if (c.IsDefaultValue) {
2821 // (expr + 0) to expr
2822 // (expr - 0) to expr
2823 // (bool? | false) to bool?
2825 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2826 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2827 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2828 return ReducedExpression.Create (b.left, b).Resolve (rc);
2832 // Optimizes (value &/&& 0) to 0
2834 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2835 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2836 return ReducedExpression.Create (side_effect, b);
2840 // Optimizes (bool? & true) to bool?
2842 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2843 return ReducedExpression.Create (b.left, b).Resolve (rc);
2847 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2848 return ReducedExpression.Create (b.left, b).Resolve (rc);
2850 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2851 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2855 c = b.left as Constant;
2857 if (c.IsDefaultValue) {
2861 // (0 + expr) to expr
2862 // (false | bool?) to bool?
2864 if (b.oper == Operator.Addition ||
2865 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2866 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2867 return ReducedExpression.Create (b.right, b).Resolve (rc);
2871 // Optimizes (false && expr) to false
2873 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2874 // No rhs side-effects
2875 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2876 return ReducedExpression.Create (c, b);
2880 // Optimizes (0 & value) to 0
2882 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2883 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2884 return ReducedExpression.Create (side_effect, b);
2888 // Optimizes (true & bool?) to bool?
2890 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2891 return ReducedExpression.Create (b.right, b).Resolve (rc);
2895 // Optimizes (true || expr) to true
2897 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2898 // No rhs side-effects
2899 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2900 return ReducedExpression.Create (c, b);
2904 if (b.oper == Operator.Multiply && c.IsOneInteger)
2905 return ReducedExpression.Create (b.right, b).Resolve (rc);
2909 var lifted = new Nullable.LiftedBinaryOperator (b);
2911 TypeSpec ltype, rtype;
2912 if (b.left.Type.IsNullableType) {
2913 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2914 ltype = left_unwrap;
2919 if (b.right.Type.IsNullableType) {
2920 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2921 rtype = right_unwrap;
2926 lifted.Left = b.left.IsNull ?
2927 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2928 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2930 lifted.Right = b.right.IsNull ?
2931 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2932 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2934 return lifted.Resolve (rc);
2937 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2938 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2943 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2946 // We are dealing with primitive types only
2948 return left == ltype && ltype == rtype;
2951 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2954 if (left == lexpr.Type && right == rexpr.Type)
2957 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2958 Convert.ImplicitConversionExists (ec, rexpr, right);
2961 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2963 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2964 return best_operator;
2966 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2970 if (left != null && best_operator.left != null) {
2971 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2975 // When second argument is same as the first one, the result is same
2977 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2978 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2981 if (result == 0 || result > 2)
2984 return result == 1 ? best_operator : this;
2988 sealed class PredefinedStringOperator : PredefinedOperator
2990 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2991 : base (type, type, op_mask, retType)
2995 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2996 : base (ltype, rtype, op_mask, retType)
3000 public override Expression ConvertResult (ResolveContext ec, Binary b)
3003 // Use original expression for nullable arguments
3005 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3007 b.left = unwrap.Original;
3009 unwrap = b.right as Nullable.Unwrap;
3011 b.right = unwrap.Original;
3013 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3014 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3017 // Start a new concat expression using converted expression
3019 return StringConcat.Create (ec, b.left, b.right, b.loc);
3023 sealed class PredefinedEqualityOperator : PredefinedOperator
3025 MethodSpec equal_method, inequal_method;
3027 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3028 : base (arg, arg, Operator.EqualityMask, retType)
3032 public override Expression ConvertResult (ResolveContext ec, Binary b)
3034 b.type = ReturnType;
3036 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3037 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3039 Arguments args = new Arguments (2);
3040 args.Add (new Argument (b.left));
3041 args.Add (new Argument (b.right));
3044 if (b.oper == Operator.Equality) {
3045 if (equal_method == null) {
3046 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3047 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3048 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3049 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3051 throw new NotImplementedException (left.GetSignatureForError ());
3054 method = equal_method;
3056 if (inequal_method == null) {
3057 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3058 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3059 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3060 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3062 throw new NotImplementedException (left.GetSignatureForError ());
3065 method = inequal_method;
3068 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3072 class PredefinedPointerOperator : PredefinedOperator
3074 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3075 : base (ltype, rtype, op_mask)
3079 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3080 : base (ltype, rtype, op_mask, retType)
3084 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3085 : base (type, op_mask, return_type)
3089 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3092 if (!lexpr.Type.IsPointer)
3095 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3099 if (right == null) {
3100 if (!rexpr.Type.IsPointer)
3103 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3110 public override Expression ConvertResult (ResolveContext ec, Binary b)
3113 b.left = EmptyCast.Create (b.left, left);
3114 } else if (right != null) {
3115 b.right = EmptyCast.Create (b.right, right);
3118 TypeSpec r_type = ReturnType;
3119 Expression left_arg, right_arg;
3120 if (r_type == null) {
3123 right_arg = b.right;
3124 r_type = b.left.Type;
3128 r_type = b.right.Type;
3132 right_arg = b.right;
3135 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3140 public enum Operator {
3141 Multiply = 0 | ArithmeticMask,
3142 Division = 1 | ArithmeticMask,
3143 Modulus = 2 | ArithmeticMask,
3144 Addition = 3 | ArithmeticMask | AdditionMask,
3145 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3147 LeftShift = 5 | ShiftMask,
3148 RightShift = 6 | ShiftMask,
3150 LessThan = 7 | ComparisonMask | RelationalMask,
3151 GreaterThan = 8 | ComparisonMask | RelationalMask,
3152 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3153 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3154 Equality = 11 | ComparisonMask | EqualityMask,
3155 Inequality = 12 | ComparisonMask | EqualityMask,
3157 BitwiseAnd = 13 | BitwiseMask,
3158 ExclusiveOr = 14 | BitwiseMask,
3159 BitwiseOr = 15 | BitwiseMask,
3161 LogicalAnd = 16 | LogicalMask,
3162 LogicalOr = 17 | LogicalMask,
3167 ValuesOnlyMask = ArithmeticMask - 1,
3168 ArithmeticMask = 1 << 5,
3170 ComparisonMask = 1 << 7,
3171 EqualityMask = 1 << 8,
3172 BitwiseMask = 1 << 9,
3173 LogicalMask = 1 << 10,
3174 AdditionMask = 1 << 11,
3175 SubtractionMask = 1 << 12,
3176 RelationalMask = 1 << 13,
3178 DecomposedMask = 1 << 19,
3179 NullableMask = 1 << 20
3183 public enum State : byte
3187 UserOperatorsExcluded = 1 << 2
3190 readonly Operator oper;
3191 Expression left, right;
3193 ConvCast.Mode enum_conversion;
3195 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3196 : this (oper, left, right, State.Compound)
3200 public Binary (Operator oper, Expression left, Expression right, State state)
3201 : this (oper, left, right)
3206 public Binary (Operator oper, Expression left, Expression right)
3207 : this (oper, left, right, left.Location)
3211 public Binary (Operator oper, Expression left, Expression right, Location loc)
3221 public bool IsCompound {
3223 return (state & State.Compound) != 0;
3227 public Operator Oper {
3233 public Expression Left {
3239 public Expression Right {
3245 public override Location StartLocation {
3247 return left.StartLocation;
3254 /// Returns a stringified representation of the Operator
3256 string OperName (Operator oper)
3260 case Operator.Multiply:
3263 case Operator.Division:
3266 case Operator.Modulus:
3269 case Operator.Addition:
3272 case Operator.Subtraction:
3275 case Operator.LeftShift:
3278 case Operator.RightShift:
3281 case Operator.LessThan:
3284 case Operator.GreaterThan:
3287 case Operator.LessThanOrEqual:
3290 case Operator.GreaterThanOrEqual:
3293 case Operator.Equality:
3296 case Operator.Inequality:
3299 case Operator.BitwiseAnd:
3302 case Operator.BitwiseOr:
3305 case Operator.ExclusiveOr:
3308 case Operator.LogicalOr:
3311 case Operator.LogicalAnd:
3315 s = oper.ToString ();
3325 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3327 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3330 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3332 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3336 l = left.Type.GetSignatureForError ();
3337 r = right.Type.GetSignatureForError ();
3339 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3343 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3345 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3348 public override void FlowAnalysis (FlowAnalysisContext fc)
3351 // Optimized version when on-true/on-false data are not needed
3353 if ((oper & Operator.LogicalMask) == 0) {
3354 left.FlowAnalysis (fc);
3355 right.FlowAnalysis (fc);
3359 left.FlowAnalysisConditional (fc);
3360 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3361 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3363 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3364 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3365 right.FlowAnalysisConditional (fc);
3367 if (oper == Operator.LogicalOr)
3368 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3370 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3373 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3375 if ((oper & Operator.LogicalMask) == 0) {
3376 base.FlowAnalysisConditional (fc);
3380 left.FlowAnalysisConditional (fc);
3381 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3382 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3384 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3385 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3386 right.FlowAnalysisConditional (fc);
3388 var lc = left as Constant;
3389 if (oper == Operator.LogicalOr) {
3390 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3391 if (lc != null && lc.IsDefaultValue)
3392 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3394 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3396 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3397 if (lc != null && !lc.IsDefaultValue)
3398 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3400 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3405 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3407 string GetOperatorExpressionTypeName ()
3410 case Operator.Addition:
3411 return IsCompound ? "AddAssign" : "Add";
3412 case Operator.BitwiseAnd:
3413 return IsCompound ? "AndAssign" : "And";
3414 case Operator.BitwiseOr:
3415 return IsCompound ? "OrAssign" : "Or";
3416 case Operator.Division:
3417 return IsCompound ? "DivideAssign" : "Divide";
3418 case Operator.ExclusiveOr:
3419 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3420 case Operator.Equality:
3422 case Operator.GreaterThan:
3423 return "GreaterThan";
3424 case Operator.GreaterThanOrEqual:
3425 return "GreaterThanOrEqual";
3426 case Operator.Inequality:
3428 case Operator.LeftShift:
3429 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3430 case Operator.LessThan:
3432 case Operator.LessThanOrEqual:
3433 return "LessThanOrEqual";
3434 case Operator.LogicalAnd:
3436 case Operator.LogicalOr:
3438 case Operator.Modulus:
3439 return IsCompound ? "ModuloAssign" : "Modulo";
3440 case Operator.Multiply:
3441 return IsCompound ? "MultiplyAssign" : "Multiply";
3442 case Operator.RightShift:
3443 return IsCompound ? "RightShiftAssign" : "RightShift";
3444 case Operator.Subtraction:
3445 return IsCompound ? "SubtractAssign" : "Subtract";
3447 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3451 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3454 case Operator.Addition:
3455 return CSharp.Operator.OpType.Addition;
3456 case Operator.BitwiseAnd:
3457 case Operator.LogicalAnd:
3458 return CSharp.Operator.OpType.BitwiseAnd;
3459 case Operator.BitwiseOr:
3460 case Operator.LogicalOr:
3461 return CSharp.Operator.OpType.BitwiseOr;
3462 case Operator.Division:
3463 return CSharp.Operator.OpType.Division;
3464 case Operator.Equality:
3465 return CSharp.Operator.OpType.Equality;
3466 case Operator.ExclusiveOr:
3467 return CSharp.Operator.OpType.ExclusiveOr;
3468 case Operator.GreaterThan:
3469 return CSharp.Operator.OpType.GreaterThan;
3470 case Operator.GreaterThanOrEqual:
3471 return CSharp.Operator.OpType.GreaterThanOrEqual;
3472 case Operator.Inequality:
3473 return CSharp.Operator.OpType.Inequality;
3474 case Operator.LeftShift:
3475 return CSharp.Operator.OpType.LeftShift;
3476 case Operator.LessThan:
3477 return CSharp.Operator.OpType.LessThan;
3478 case Operator.LessThanOrEqual:
3479 return CSharp.Operator.OpType.LessThanOrEqual;
3480 case Operator.Modulus:
3481 return CSharp.Operator.OpType.Modulus;
3482 case Operator.Multiply:
3483 return CSharp.Operator.OpType.Multiply;
3484 case Operator.RightShift:
3485 return CSharp.Operator.OpType.RightShift;
3486 case Operator.Subtraction:
3487 return CSharp.Operator.OpType.Subtraction;
3489 throw new InternalErrorException (op.ToString ());
3493 public override bool ContainsEmitWithAwait ()
3495 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3498 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3503 case Operator.Multiply:
3504 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3505 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3506 opcode = OpCodes.Mul_Ovf;
3507 else if (!IsFloat (l))
3508 opcode = OpCodes.Mul_Ovf_Un;
3510 opcode = OpCodes.Mul;
3512 opcode = OpCodes.Mul;
3516 case Operator.Division:
3518 opcode = OpCodes.Div_Un;
3520 opcode = OpCodes.Div;
3523 case Operator.Modulus:
3525 opcode = OpCodes.Rem_Un;
3527 opcode = OpCodes.Rem;
3530 case Operator.Addition:
3531 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3532 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3533 opcode = OpCodes.Add_Ovf;
3534 else if (!IsFloat (l))
3535 opcode = OpCodes.Add_Ovf_Un;
3537 opcode = OpCodes.Add;
3539 opcode = OpCodes.Add;
3542 case Operator.Subtraction:
3543 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3544 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3545 opcode = OpCodes.Sub_Ovf;
3546 else if (!IsFloat (l))
3547 opcode = OpCodes.Sub_Ovf_Un;
3549 opcode = OpCodes.Sub;
3551 opcode = OpCodes.Sub;
3554 case Operator.RightShift:
3555 if (!(right is IntConstant)) {
3556 ec.EmitInt (GetShiftMask (l));
3557 ec.Emit (OpCodes.And);
3561 opcode = OpCodes.Shr_Un;
3563 opcode = OpCodes.Shr;
3566 case Operator.LeftShift:
3567 if (!(right is IntConstant)) {
3568 ec.EmitInt (GetShiftMask (l));
3569 ec.Emit (OpCodes.And);
3572 opcode = OpCodes.Shl;
3575 case Operator.Equality:
3576 opcode = OpCodes.Ceq;
3579 case Operator.Inequality:
3580 ec.Emit (OpCodes.Ceq);
3583 opcode = OpCodes.Ceq;
3586 case Operator.LessThan:
3588 opcode = OpCodes.Clt_Un;
3590 opcode = OpCodes.Clt;
3593 case Operator.GreaterThan:
3595 opcode = OpCodes.Cgt_Un;
3597 opcode = OpCodes.Cgt;
3600 case Operator.LessThanOrEqual:
3601 if (IsUnsigned (l) || IsFloat (l))
3602 ec.Emit (OpCodes.Cgt_Un);
3604 ec.Emit (OpCodes.Cgt);
3607 opcode = OpCodes.Ceq;
3610 case Operator.GreaterThanOrEqual:
3611 if (IsUnsigned (l) || IsFloat (l))
3612 ec.Emit (OpCodes.Clt_Un);
3614 ec.Emit (OpCodes.Clt);
3618 opcode = OpCodes.Ceq;
3621 case Operator.BitwiseOr:
3622 opcode = OpCodes.Or;
3625 case Operator.BitwiseAnd:
3626 opcode = OpCodes.And;
3629 case Operator.ExclusiveOr:
3630 opcode = OpCodes.Xor;
3634 throw new InternalErrorException (oper.ToString ());
3640 static int GetShiftMask (TypeSpec type)
3642 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3645 static bool IsUnsigned (TypeSpec t)
3647 switch (t.BuiltinType) {
3648 case BuiltinTypeSpec.Type.Char:
3649 case BuiltinTypeSpec.Type.UInt:
3650 case BuiltinTypeSpec.Type.ULong:
3651 case BuiltinTypeSpec.Type.UShort:
3652 case BuiltinTypeSpec.Type.Byte:
3659 static bool IsFloat (TypeSpec t)
3661 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3664 public Expression ResolveOperator (ResolveContext rc)
3666 eclass = ExprClass.Value;
3668 TypeSpec l = left.Type;
3669 TypeSpec r = right.Type;
3671 bool primitives_only = false;
3674 // Handles predefined primitive types
3676 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3677 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3678 if ((oper & Operator.ShiftMask) == 0) {
3679 if (!DoBinaryOperatorPromotion (rc))
3682 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3686 if (l.IsPointer || r.IsPointer)
3687 return ResolveOperatorPointer (rc, l, r);
3690 if ((state & State.UserOperatorsExcluded) == 0) {
3691 expr = ResolveUserOperator (rc, left, right);
3696 bool lenum = l.IsEnum;
3697 bool renum = r.IsEnum;
3698 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3702 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3703 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3708 if ((oper & Operator.BitwiseMask) != 0) {
3709 expr = EmptyCast.Create (expr, type);
3710 enum_conversion = GetEnumResultCast (type);
3712 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3713 expr = OptimizeAndOperation (expr);
3717 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3718 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3721 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3722 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3726 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3729 // We cannot break here there is also Enum + String possible match
3730 // which is not ambiguous with predefined enum operators
3733 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3734 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3738 } else if (l.IsDelegate || r.IsDelegate) {
3742 expr = ResolveOperatorDelegate (rc, l, r);
3744 // TODO: Can this be ambiguous
3752 // Equality operators are more complicated
3754 if ((oper & Operator.EqualityMask) != 0) {
3755 return ResolveEquality (rc, l, r, primitives_only);
3758 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3762 if (primitives_only)
3766 // Lifted operators have lower priority
3768 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3771 static bool IsEnumOrNullableEnum (TypeSpec type)
3773 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3777 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3778 // if 'left' is not an enumeration constant, create one from the type of 'right'
3779 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3782 case Operator.BitwiseOr:
3783 case Operator.BitwiseAnd:
3784 case Operator.ExclusiveOr:
3785 case Operator.Equality:
3786 case Operator.Inequality:
3787 case Operator.LessThan:
3788 case Operator.LessThanOrEqual:
3789 case Operator.GreaterThan:
3790 case Operator.GreaterThanOrEqual:
3791 if (left.Type.IsEnum)
3794 if (left.IsZeroInteger)
3795 return left.Reduce (ec, right.Type);
3799 case Operator.Addition:
3800 case Operator.Subtraction:
3803 case Operator.Multiply:
3804 case Operator.Division:
3805 case Operator.Modulus:
3806 case Operator.LeftShift:
3807 case Operator.RightShift:
3808 if (right.Type.IsEnum || left.Type.IsEnum)
3817 // The `|' operator used on types which were extended is dangerous
3819 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3821 OpcodeCast lcast = left as OpcodeCast;
3822 if (lcast != null) {
3823 if (IsUnsigned (lcast.UnderlyingType))
3827 OpcodeCast rcast = right as OpcodeCast;
3828 if (rcast != null) {
3829 if (IsUnsigned (rcast.UnderlyingType))
3833 if (lcast == null && rcast == null)
3836 // FIXME: consider constants
3838 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3839 ec.Report.Warning (675, 3, loc,
3840 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3841 ltype.GetSignatureForError ());
3844 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3846 return new PredefinedOperator[] {
3848 // Pointer arithmetic:
3850 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3851 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3852 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3853 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3855 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3856 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3857 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3858 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3861 // T* operator + (int y, T* x);
3862 // T* operator + (uint y, T *x);
3863 // T* operator + (long y, T *x);
3864 // T* operator + (ulong y, T *x);
3866 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3867 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3868 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3869 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3872 // long operator - (T* x, T *y)
3874 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3878 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3880 TypeSpec bool_type = types.Bool;
3883 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3884 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3885 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3886 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3887 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3888 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3889 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3891 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3892 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3893 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3894 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3895 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3896 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3897 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3899 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3900 // Remaining string operators are in lifted tables
3902 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3904 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3905 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3906 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3910 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3912 var types = module.Compiler.BuiltinTypes;
3915 // Not strictly lifted but need to be in second group otherwise expressions like
3916 // int + null would resolve to +(object, string) instead of +(int?, int?)
3918 var string_operators = new [] {
3919 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3920 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3923 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3924 if (nullable == null)
3925 return string_operators;
3927 var bool_type = types.Bool;
3929 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3930 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3931 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3932 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3933 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3934 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3935 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3936 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3939 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3940 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3941 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3942 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3943 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3944 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3945 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3947 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3948 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3949 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3950 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3951 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3952 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3953 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3955 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3957 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3958 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3959 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3961 string_operators [0],
3962 string_operators [1]
3966 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3968 TypeSpec bool_type = types.Bool;
3971 new PredefinedEqualityOperator (types.String, bool_type),
3972 new PredefinedEqualityOperator (types.Delegate, bool_type),
3973 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3975 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3976 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3977 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3978 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3979 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3980 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3984 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3986 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3988 if (nullable == null)
3989 return new PredefinedOperator [0];
3991 var types = module.Compiler.BuiltinTypes;
3992 var bool_type = types.Bool;
3993 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3994 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3995 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3996 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3997 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3998 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3999 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4000 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4003 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4005 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4006 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4007 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4008 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4009 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4010 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4015 // 7.2.6.2 Binary numeric promotions
4017 bool DoBinaryOperatorPromotion (ResolveContext rc)
4019 TypeSpec ltype = left.Type;
4020 if (ltype.IsNullableType) {
4021 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4025 // This is numeric promotion code only
4027 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4030 TypeSpec rtype = right.Type;
4031 if (rtype.IsNullableType) {
4032 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4035 var lb = ltype.BuiltinType;
4036 var rb = rtype.BuiltinType;
4040 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4041 type = rc.BuiltinTypes.Decimal;
4042 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4043 type = rc.BuiltinTypes.Double;
4044 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4045 type = rc.BuiltinTypes.Float;
4046 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4047 type = rc.BuiltinTypes.ULong;
4049 if (IsSignedType (lb)) {
4050 expr = ConvertSignedConstant (left, type);
4054 } else if (IsSignedType (rb)) {
4055 expr = ConvertSignedConstant (right, type);
4061 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4062 type = rc.BuiltinTypes.Long;
4063 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4064 type = rc.BuiltinTypes.UInt;
4066 if (IsSignedType (lb)) {
4067 expr = ConvertSignedConstant (left, type);
4069 type = rc.BuiltinTypes.Long;
4070 } else if (IsSignedType (rb)) {
4071 expr = ConvertSignedConstant (right, type);
4073 type = rc.BuiltinTypes.Long;
4076 type = rc.BuiltinTypes.Int;
4079 if (ltype != type) {
4080 expr = PromoteExpression (rc, left, type);
4087 if (rtype != type) {
4088 expr = PromoteExpression (rc, right, type);
4098 static bool IsSignedType (BuiltinTypeSpec.Type type)
4101 case BuiltinTypeSpec.Type.Int:
4102 case BuiltinTypeSpec.Type.Short:
4103 case BuiltinTypeSpec.Type.SByte:
4104 case BuiltinTypeSpec.Type.Long:
4111 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4113 var c = expr as Constant;
4117 return c.ConvertImplicitly (type);
4120 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4122 if (expr.Type.IsNullableType) {
4123 return Convert.ImplicitConversionStandard (rc, expr,
4124 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4127 var c = expr as Constant;
4129 return c.ConvertImplicitly (type);
4131 return Convert.ImplicitNumericConversion (expr, type);
4134 protected override Expression DoResolve (ResolveContext ec)
4139 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4140 left = ((ParenthesizedExpression) left).Expr;
4141 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4145 if (left.eclass == ExprClass.Type) {
4146 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4150 left = left.Resolve (ec);
4155 right = right.Resolve (ec);
4159 Constant lc = left as Constant;
4160 Constant rc = right as Constant;
4162 // The conversion rules are ignored in enum context but why
4163 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4164 lc = EnumLiftUp (ec, lc, rc);
4166 rc = EnumLiftUp (ec, rc, lc);
4169 if (rc != null && lc != null) {
4170 int prev_e = ec.Report.Errors;
4171 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4172 if (e != null || ec.Report.Errors != prev_e)
4176 // Comparison warnings
4177 if ((oper & Operator.ComparisonMask) != 0) {
4178 if (left.Equals (right)) {
4179 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4181 CheckOutOfRangeComparison (ec, lc, right.Type);
4182 CheckOutOfRangeComparison (ec, rc, left.Type);
4185 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4186 return DoResolveDynamic (ec);
4188 return DoResolveCore (ec, left, right);
4191 Expression DoResolveDynamic (ResolveContext rc)
4194 var rt = right.Type;
4195 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4196 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4197 Error_OperatorCannotBeApplied (rc, left, right);
4204 // Special handling for logical boolean operators which require rhs not to be
4205 // evaluated based on lhs value
4207 if ((oper & Operator.LogicalMask) != 0) {
4208 Expression cond_left, cond_right, expr;
4210 args = new Arguments (2);
4212 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4213 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4215 var cond_args = new Arguments (1);
4216 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4219 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4220 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4222 left = temp.CreateReferenceExpression (rc, loc);
4223 if (oper == Operator.LogicalAnd) {
4224 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4227 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4231 args.Add (new Argument (left));
4232 args.Add (new Argument (right));
4233 cond_right = new DynamicExpressionStatement (this, args, loc);
4235 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4237 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4238 rc.Report.Error (7083, left.Location,
4239 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4240 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4244 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4245 args.Add (new Argument (right));
4246 right = new DynamicExpressionStatement (this, args, loc);
4249 // bool && dynamic => (temp = left) ? temp && right : temp;
4250 // bool || dynamic => (temp = left) ? temp : temp || right;
4252 if (oper == Operator.LogicalAnd) {
4254 cond_right = temp.CreateReferenceExpression (rc, loc);
4256 cond_left = temp.CreateReferenceExpression (rc, loc);
4260 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4263 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4266 args = new Arguments (2);
4267 args.Add (new Argument (left));
4268 args.Add (new Argument (right));
4269 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4272 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4274 Expression expr = ResolveOperator (ec);
4276 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4278 if (left == null || right == null)
4279 throw new InternalErrorException ("Invalid conversion");
4281 if (oper == Operator.BitwiseOr)
4282 CheckBitwiseOrOnSignExtended (ec);
4287 public override SLE.Expression MakeExpression (BuilderContext ctx)
4289 return MakeExpression (ctx, left, right);
4292 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4294 var le = left.MakeExpression (ctx);
4295 var re = right.MakeExpression (ctx);
4296 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4299 case Operator.Addition:
4300 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4301 case Operator.BitwiseAnd:
4302 return SLE.Expression.And (le, re);
4303 case Operator.BitwiseOr:
4304 return SLE.Expression.Or (le, re);
4305 case Operator.Division:
4306 return SLE.Expression.Divide (le, re);
4307 case Operator.Equality:
4308 return SLE.Expression.Equal (le, re);
4309 case Operator.ExclusiveOr:
4310 return SLE.Expression.ExclusiveOr (le, re);
4311 case Operator.GreaterThan:
4312 return SLE.Expression.GreaterThan (le, re);
4313 case Operator.GreaterThanOrEqual:
4314 return SLE.Expression.GreaterThanOrEqual (le, re);
4315 case Operator.Inequality:
4316 return SLE.Expression.NotEqual (le, re);
4317 case Operator.LeftShift:
4318 return SLE.Expression.LeftShift (le, re);
4319 case Operator.LessThan:
4320 return SLE.Expression.LessThan (le, re);
4321 case Operator.LessThanOrEqual:
4322 return SLE.Expression.LessThanOrEqual (le, re);
4323 case Operator.LogicalAnd:
4324 return SLE.Expression.AndAlso (le, re);
4325 case Operator.LogicalOr:
4326 return SLE.Expression.OrElse (le, re);
4327 case Operator.Modulus:
4328 return SLE.Expression.Modulo (le, re);
4329 case Operator.Multiply:
4330 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4331 case Operator.RightShift:
4332 return SLE.Expression.RightShift (le, re);
4333 case Operator.Subtraction:
4334 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4336 throw new NotImplementedException (oper.ToString ());
4341 // D operator + (D x, D y)
4342 // D operator - (D x, D y)
4344 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4346 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4348 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4349 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4354 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4355 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4365 MethodSpec method = null;
4366 Arguments args = new Arguments (2);
4367 args.Add (new Argument (left));
4368 args.Add (new Argument (right));
4370 if (oper == Operator.Addition) {
4371 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4372 } else if (oper == Operator.Subtraction) {
4373 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4377 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4379 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4380 return new ClassCast (expr, l);
4384 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4386 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4389 // bool operator == (E x, E y);
4390 // bool operator != (E x, E y);
4391 // bool operator < (E x, E y);
4392 // bool operator > (E x, E y);
4393 // bool operator <= (E x, E y);
4394 // bool operator >= (E x, E y);
4396 // E operator & (E x, E y);
4397 // E operator | (E x, E y);
4398 // E operator ^ (E x, E y);
4401 if ((oper & Operator.ComparisonMask) != 0) {
4402 type = rc.BuiltinTypes.Bool;
4408 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4414 if (ltype == rtype) {
4418 var lifted = new Nullable.LiftedBinaryOperator (this);
4420 lifted.Right = right;
4421 return lifted.Resolve (rc);
4424 if (renum && !ltype.IsNullableType) {
4425 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4430 } else if (lenum && !rtype.IsNullableType) {
4431 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4439 // Now try lifted version of predefined operator
4441 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4442 if (nullable_type != null) {
4443 if (renum && !ltype.IsNullableType) {
4444 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4446 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4449 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4452 if ((oper & Operator.BitwiseMask) != 0)
4456 if ((oper & Operator.BitwiseMask) != 0)
4457 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4459 return CreateLiftedValueTypeResult (rc, rtype);
4463 var lifted = new Nullable.LiftedBinaryOperator (this);
4465 lifted.Right = right;
4466 return lifted.Resolve (rc);
4468 } else if (lenum && !rtype.IsNullableType) {
4469 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4471 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4474 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4477 if ((oper & Operator.BitwiseMask) != 0)
4481 if ((oper & Operator.BitwiseMask) != 0)
4482 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4484 return CreateLiftedValueTypeResult (rc, ltype);
4488 var lifted = new Nullable.LiftedBinaryOperator (this);
4490 lifted.Right = expr;
4491 return lifted.Resolve (rc);
4493 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4494 Nullable.Unwrap unwrap = null;
4495 if (left.IsNull || right.IsNull) {
4496 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4497 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4499 if ((oper & Operator.RelationalMask) != 0)
4500 return CreateLiftedValueTypeResult (rc, rtype);
4502 if ((oper & Operator.BitwiseMask) != 0)
4503 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4506 return CreateLiftedValueTypeResult (rc, left.Type);
4508 // Equality operators are valid between E? and null
4510 unwrap = new Nullable.Unwrap (right);
4512 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4516 if ((oper & Operator.BitwiseMask) != 0)
4521 var lifted = new Nullable.LiftedBinaryOperator (this);
4523 lifted.Right = right;
4524 lifted.UnwrapRight = unwrap;
4525 return lifted.Resolve (rc);
4527 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4528 Nullable.Unwrap unwrap = null;
4529 if (right.IsNull || left.IsNull) {
4530 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4531 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4533 if ((oper & Operator.RelationalMask) != 0)
4534 return CreateLiftedValueTypeResult (rc, ltype);
4536 if ((oper & Operator.BitwiseMask) != 0)
4537 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4540 return CreateLiftedValueTypeResult (rc, right.Type);
4542 // Equality operators are valid between E? and null
4544 unwrap = new Nullable.Unwrap (left);
4546 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4550 if ((oper & Operator.BitwiseMask) != 0)
4555 var lifted = new Nullable.LiftedBinaryOperator (this);
4557 lifted.UnwrapLeft = unwrap;
4558 lifted.Right = expr;
4559 return lifted.Resolve (rc);
4567 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4569 TypeSpec underlying_type;
4570 if (expr.Type.IsNullableType) {
4571 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4573 underlying_type = EnumSpec.GetUnderlyingType (nt);
4575 underlying_type = nt;
4576 } else if (expr.Type.IsEnum) {
4577 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4579 underlying_type = expr.Type;
4582 switch (underlying_type.BuiltinType) {
4583 case BuiltinTypeSpec.Type.SByte:
4584 case BuiltinTypeSpec.Type.Byte:
4585 case BuiltinTypeSpec.Type.Short:
4586 case BuiltinTypeSpec.Type.UShort:
4587 underlying_type = rc.BuiltinTypes.Int;
4591 if (expr.Type.IsNullableType || liftType)
4592 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4594 if (expr.Type == underlying_type)
4597 return EmptyCast.Create (expr, underlying_type);
4600 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4603 // U operator - (E e, E f)
4604 // E operator - (E e, U x) // Internal decomposition operator
4605 // E operator - (U x, E e) // Internal decomposition operator
4607 // E operator + (E e, U x)
4608 // E operator + (U x, E e)
4617 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4623 if (!enum_type.IsNullableType) {
4624 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4626 if (oper == Operator.Subtraction)
4627 expr = ConvertEnumSubtractionResult (rc, expr);
4629 expr = ConvertEnumAdditionalResult (expr, enum_type);
4631 enum_conversion = GetEnumResultCast (expr.Type);
4636 var nullable = rc.Module.PredefinedTypes.Nullable;
4639 // Don't try nullable version when nullable type is undefined
4641 if (!nullable.IsDefined)
4644 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4647 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4649 if (oper == Operator.Subtraction)
4650 expr = ConvertEnumSubtractionResult (rc, expr);
4652 expr = ConvertEnumAdditionalResult (expr, enum_type);
4654 enum_conversion = GetEnumResultCast (expr.Type);
4660 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4662 return EmptyCast.Create (expr, enumType);
4665 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4668 // Enumeration subtraction has different result type based on
4671 TypeSpec result_type;
4672 if (left.Type == right.Type) {
4673 var c = right as EnumConstant;
4674 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4676 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4677 // E which is not what expressions E - 1 or 0 - E return
4679 result_type = left.Type;
4681 result_type = left.Type.IsNullableType ?
4682 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4683 EnumSpec.GetUnderlyingType (left.Type);
4686 if (IsEnumOrNullableEnum (left.Type)) {
4687 result_type = left.Type;
4689 result_type = right.Type;
4692 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4693 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4696 return EmptyCast.Create (expr, result_type);
4699 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4701 if (type.IsNullableType)
4702 type = Nullable.NullableInfo.GetUnderlyingType (type);
4705 type = EnumSpec.GetUnderlyingType (type);
4707 switch (type.BuiltinType) {
4708 case BuiltinTypeSpec.Type.SByte:
4709 return ConvCast.Mode.I4_I1;
4710 case BuiltinTypeSpec.Type.Byte:
4711 return ConvCast.Mode.I4_U1;
4712 case BuiltinTypeSpec.Type.Short:
4713 return ConvCast.Mode.I4_I2;
4714 case BuiltinTypeSpec.Type.UShort:
4715 return ConvCast.Mode.I4_U2;
4722 // Equality operators rules
4724 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4727 type = ec.BuiltinTypes.Bool;
4728 bool no_arg_conv = false;
4730 if (!primitives_only) {
4733 // a, Both operands are reference-type values or the value null
4734 // b, One operand is a value of type T where T is a type-parameter and
4735 // the other operand is the value null. Furthermore T does not have the
4736 // value type constraint
4738 // LAMESPEC: Very confusing details in the specification, basically any
4739 // reference like type-parameter is allowed
4741 var tparam_l = l as TypeParameterSpec;
4742 var tparam_r = r as TypeParameterSpec;
4743 if (tparam_l != null) {
4744 if (right is NullLiteral) {
4745 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4748 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4752 if (!tparam_l.IsReferenceType)
4755 l = tparam_l.GetEffectiveBase ();
4756 left = new BoxedCast (left, l);
4757 } else if (left is NullLiteral && tparam_r == null) {
4758 if (TypeSpec.IsReferenceType (r))
4761 if (r.Kind == MemberKind.InternalCompilerType)
4765 if (tparam_r != null) {
4766 if (left is NullLiteral) {
4767 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4770 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4774 if (!tparam_r.IsReferenceType)
4777 r = tparam_r.GetEffectiveBase ();
4778 right = new BoxedCast (right, r);
4779 } else if (right is NullLiteral) {
4780 if (TypeSpec.IsReferenceType (l))
4783 if (l.Kind == MemberKind.InternalCompilerType)
4788 // LAMESPEC: method groups can be compared when they convert to other side delegate
4791 if (right.eclass == ExprClass.MethodGroup) {
4792 result = Convert.ImplicitConversion (ec, right, l, loc);
4798 } else if (r.IsDelegate && l != r) {
4801 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4802 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4809 no_arg_conv = l == r && !l.IsStruct;
4814 // bool operator != (string a, string b)
4815 // bool operator == (string a, string b)
4817 // bool operator != (Delegate a, Delegate b)
4818 // bool operator == (Delegate a, Delegate b)
4820 // bool operator != (bool a, bool b)
4821 // bool operator == (bool a, bool b)
4823 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4824 // they implement an implicit conversion to any of types above. This does
4825 // not apply when both operands are of same reference type
4827 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4828 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4833 // Now try lifted version of predefined operators
4835 if (no_arg_conv && !l.IsNullableType) {
4837 // Optimizes cases which won't match
4840 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4846 // The == and != operators permit one operand to be a value of a nullable
4847 // type and the other to be the null literal, even if no predefined or user-defined
4848 // operator (in unlifted or lifted form) exists for the operation.
4850 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4851 var lifted = new Nullable.LiftedBinaryOperator (this);
4853 lifted.Right = right;
4854 return lifted.Resolve (ec);
4859 // bool operator != (object a, object b)
4860 // bool operator == (object a, object b)
4862 // An explicit reference conversion exists from the
4863 // type of either operand to the type of the other operand.
4866 // Optimize common path
4868 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4871 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4872 !Convert.ExplicitReferenceConversionExists (r, l))
4875 // Reject allowed explicit conversions like int->object
4876 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4879 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4880 ec.Report.Warning (253, 2, loc,
4881 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4882 l.GetSignatureForError ());
4884 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4885 ec.Report.Warning (252, 2, loc,
4886 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4887 r.GetSignatureForError ());
4893 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4896 // bool operator == (void* x, void* y);
4897 // bool operator != (void* x, void* y);
4898 // bool operator < (void* x, void* y);
4899 // bool operator > (void* x, void* y);
4900 // bool operator <= (void* x, void* y);
4901 // bool operator >= (void* x, void* y);
4903 if ((oper & Operator.ComparisonMask) != 0) {
4906 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4913 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4919 type = ec.BuiltinTypes.Bool;
4923 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4927 // Build-in operators method overloading
4929 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4931 PredefinedOperator best_operator = null;
4932 TypeSpec l = left.Type;
4933 TypeSpec r = right.Type;
4934 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4936 foreach (PredefinedOperator po in operators) {
4937 if ((po.OperatorsMask & oper_mask) == 0)
4940 if (primitives_only) {
4941 if (!po.IsPrimitiveApplicable (l, r))
4944 if (!po.IsApplicable (ec, left, right))
4948 if (best_operator == null) {
4950 if (primitives_only)
4956 best_operator = po.ResolveBetterOperator (ec, best_operator);
4958 if (best_operator == null) {
4959 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4960 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4967 if (best_operator == null)
4970 return best_operator.ConvertResult (ec, this);
4974 // Optimize & constant expressions with 0 value
4976 Expression OptimizeAndOperation (Expression expr)
4978 Constant rc = right as Constant;
4979 Constant lc = left as Constant;
4980 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4982 // The result is a constant with side-effect
4984 Constant side_effect = rc == null ?
4985 new SideEffectConstant (lc, right, loc) :
4986 new SideEffectConstant (rc, left, loc);
4988 return ReducedExpression.Create (side_effect, expr);
4995 // Value types can be compared with the null literal because of the lifting
4996 // language rules. However the result is always true or false.
4998 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5000 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5001 type = rc.BuiltinTypes.Bool;
5005 // FIXME: Handle side effect constants
5006 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5008 if ((Oper & Operator.EqualityMask) != 0) {
5009 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5010 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5012 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5013 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5020 // Performs user-operator overloading
5022 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5024 Expression oper_expr;
5026 var op = ConvertBinaryToUserOperator (oper);
5028 if (l.IsNullableType)
5029 l = Nullable.NullableInfo.GetUnderlyingType (l);
5031 if (r.IsNullableType)
5032 r = Nullable.NullableInfo.GetUnderlyingType (r);
5034 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5035 IList<MemberSpec> right_operators = null;
5038 right_operators = MemberCache.GetUserOperator (r, op, false);
5039 if (right_operators == null && left_operators == null)
5041 } else if (left_operators == null) {
5045 Arguments args = new Arguments (2);
5046 Argument larg = new Argument (left);
5048 Argument rarg = new Argument (right);
5052 // User-defined operator implementations always take precedence
5053 // over predefined operator implementations
5055 if (left_operators != null && right_operators != null) {
5056 left_operators = CombineUserOperators (left_operators, right_operators);
5057 } else if (right_operators != null) {
5058 left_operators = right_operators;
5061 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5062 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5064 var res = new OverloadResolver (left_operators, restr, loc);
5066 var oper_method = res.ResolveOperator (rc, ref args);
5067 if (oper_method == null) {
5069 // Logical && and || cannot be lifted
5071 if ((oper & Operator.LogicalMask) != 0)
5075 // Apply lifted user operators only for liftable types. Implicit conversion
5076 // to nullable types is not allowed
5078 if (!IsLiftedOperatorApplicable ())
5081 // TODO: Cache the result in module container
5082 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5083 if (lifted_methods == null)
5086 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5088 oper_method = res.ResolveOperator (rc, ref args);
5089 if (oper_method == null)
5092 MethodSpec best_original = null;
5093 foreach (MethodSpec ms in left_operators) {
5094 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5100 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5102 // Expression trees use lifted notation in this case
5104 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5105 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5108 var ptypes = best_original.Parameters.Types;
5110 if (left.IsNull || right.IsNull) {
5112 // The lifted operator produces a null value if one or both operands are null
5114 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5115 type = oper_method.ReturnType;
5116 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5120 // The lifted operator produces the value false if one or both operands are null for
5121 // relational operators.
5123 if ((oper & Operator.RelationalMask) != 0) {
5125 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5126 // because return type is actually bool
5128 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5131 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5132 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5136 type = oper_method.ReturnType;
5137 var lifted = new Nullable.LiftedBinaryOperator (this);
5138 lifted.UserOperator = best_original;
5140 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5141 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5144 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5145 lifted.UnwrapRight = new Nullable.Unwrap (right);
5148 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5149 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5151 return lifted.Resolve (rc);
5154 if ((oper & Operator.LogicalMask) != 0) {
5155 // TODO: CreateExpressionTree is allocated every time
5156 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5157 oper == Operator.LogicalAnd, loc).Resolve (rc);
5159 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5162 this.left = larg.Expr;
5163 this.right = rarg.Expr;
5168 bool IsLiftedOperatorApplicable ()
5170 if (left.Type.IsNullableType) {
5171 if ((oper & Operator.EqualityMask) != 0)
5172 return !right.IsNull;
5177 if (right.Type.IsNullableType) {
5178 if ((oper & Operator.EqualityMask) != 0)
5179 return !left.IsNull;
5184 if (TypeSpec.IsValueType (left.Type))
5185 return right.IsNull;
5187 if (TypeSpec.IsValueType (right.Type))
5193 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5195 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5196 if (nullable_type == null)
5200 // Lifted operators permit predefined and user-defined operators that operate
5201 // on non-nullable value types to also be used with nullable forms of those types.
5202 // Lifted operators are constructed from predefined and user-defined operators
5203 // that meet certain requirements
5205 List<MemberSpec> lifted = null;
5206 foreach (MethodSpec oper in operators) {
5208 if ((Oper & Operator.ComparisonMask) != 0) {
5210 // Result type must be of type bool for lifted comparison operators
5212 rt = oper.ReturnType;
5213 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5216 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5222 var ptypes = oper.Parameters.Types;
5223 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5227 // LAMESPEC: I am not sure why but for equality operators to be lifted
5228 // both types have to match
5230 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5234 lifted = new List<MemberSpec> ();
5237 // The lifted form is constructed by adding a single ? modifier to each operand and
5238 // result type except for comparison operators where return type is bool
5241 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5243 var parameters = ParametersCompiled.CreateFullyResolved (
5244 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5245 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5247 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5248 rt, parameters, oper.Modifiers);
5250 lifted.Add (lifted_op);
5257 // Merge two sets of user operators into one, they are mostly distinguish
5258 // except when they share base type and it contains an operator
5260 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5262 var combined = new List<MemberSpec> (left.Count + right.Count);
5263 combined.AddRange (left);
5264 foreach (var r in right) {
5266 foreach (var l in left) {
5267 if (l.DeclaringType == r.DeclaringType) {
5280 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5282 if (c is IntegralConstant || c is CharConstant) {
5284 c.ConvertExplicitly (true, type);
5285 } catch (OverflowException) {
5286 ec.Report.Warning (652, 2, loc,
5287 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5288 type.GetSignatureForError ());
5294 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5295 /// context of a conditional bool expression. This function will return
5296 /// false if it is was possible to use EmitBranchable, or true if it was.
5298 /// The expression's code is generated, and we will generate a branch to `target'
5299 /// if the resulting expression value is equal to isTrue
5301 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5303 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5304 left = left.EmitToField (ec);
5306 if ((oper & Operator.LogicalMask) == 0) {
5307 right = right.EmitToField (ec);
5312 // This is more complicated than it looks, but its just to avoid
5313 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5314 // but on top of that we want for == and != to use a special path
5315 // if we are comparing against null
5317 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5318 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5321 // put the constant on the rhs, for simplicity
5323 if (left is Constant) {
5324 Expression swap = right;
5330 // brtrue/brfalse works with native int only
5332 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5333 left.EmitBranchable (ec, target, my_on_true);
5336 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5337 // right is a boolean, and it's not 'false' => it is 'true'
5338 left.EmitBranchable (ec, target, !my_on_true);
5342 } else if (oper == Operator.LogicalAnd) {
5345 Label tests_end = ec.DefineLabel ();
5347 left.EmitBranchable (ec, tests_end, false);
5348 right.EmitBranchable (ec, target, true);
5349 ec.MarkLabel (tests_end);
5352 // This optimizes code like this
5353 // if (true && i > 4)
5355 if (!(left is Constant))
5356 left.EmitBranchable (ec, target, false);
5358 if (!(right is Constant))
5359 right.EmitBranchable (ec, target, false);
5364 } else if (oper == Operator.LogicalOr){
5366 left.EmitBranchable (ec, target, true);
5367 right.EmitBranchable (ec, target, true);
5370 Label tests_end = ec.DefineLabel ();
5371 left.EmitBranchable (ec, tests_end, true);
5372 right.EmitBranchable (ec, target, false);
5373 ec.MarkLabel (tests_end);
5378 } else if ((oper & Operator.ComparisonMask) == 0) {
5379 base.EmitBranchable (ec, target, on_true);
5386 TypeSpec t = left.Type;
5387 bool is_float = IsFloat (t);
5388 bool is_unsigned = is_float || IsUnsigned (t);
5391 case Operator.Equality:
5393 ec.Emit (OpCodes.Beq, target);
5395 ec.Emit (OpCodes.Bne_Un, target);
5398 case Operator.Inequality:
5400 ec.Emit (OpCodes.Bne_Un, target);
5402 ec.Emit (OpCodes.Beq, target);
5405 case Operator.LessThan:
5407 if (is_unsigned && !is_float)
5408 ec.Emit (OpCodes.Blt_Un, target);
5410 ec.Emit (OpCodes.Blt, target);
5413 ec.Emit (OpCodes.Bge_Un, target);
5415 ec.Emit (OpCodes.Bge, target);
5418 case Operator.GreaterThan:
5420 if (is_unsigned && !is_float)
5421 ec.Emit (OpCodes.Bgt_Un, target);
5423 ec.Emit (OpCodes.Bgt, target);
5426 ec.Emit (OpCodes.Ble_Un, target);
5428 ec.Emit (OpCodes.Ble, target);
5431 case Operator.LessThanOrEqual:
5433 if (is_unsigned && !is_float)
5434 ec.Emit (OpCodes.Ble_Un, target);
5436 ec.Emit (OpCodes.Ble, target);
5439 ec.Emit (OpCodes.Bgt_Un, target);
5441 ec.Emit (OpCodes.Bgt, target);
5445 case Operator.GreaterThanOrEqual:
5447 if (is_unsigned && !is_float)
5448 ec.Emit (OpCodes.Bge_Un, target);
5450 ec.Emit (OpCodes.Bge, target);
5453 ec.Emit (OpCodes.Blt_Un, target);
5455 ec.Emit (OpCodes.Blt, target);
5458 throw new InternalErrorException (oper.ToString ());
5462 public override void Emit (EmitContext ec)
5464 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5465 left = left.EmitToField (ec);
5467 if ((oper & Operator.LogicalMask) == 0) {
5468 right = right.EmitToField (ec);
5473 // Handle short-circuit operators differently
5476 if ((oper & Operator.LogicalMask) != 0) {
5477 Label load_result = ec.DefineLabel ();
5478 Label end = ec.DefineLabel ();
5480 bool is_or = oper == Operator.LogicalOr;
5481 left.EmitBranchable (ec, load_result, is_or);
5483 ec.Emit (OpCodes.Br_S, end);
5485 ec.MarkLabel (load_result);
5486 ec.EmitInt (is_or ? 1 : 0);
5492 // Optimize zero-based operations which cannot be optimized at expression level
5494 if (oper == Operator.Subtraction) {
5495 var lc = left as IntegralConstant;
5496 if (lc != null && lc.IsDefaultValue) {
5498 ec.Emit (OpCodes.Neg);
5503 EmitOperator (ec, left, right);
5506 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5511 EmitOperatorOpcode (ec, oper, left.Type, right);
5514 // Emit result enumerable conversion this way because it's quite complicated get it
5515 // to resolved tree because expression tree cannot see it.
5517 if (enum_conversion != 0)
5518 ConvCast.Emit (ec, enum_conversion);
5521 public override void EmitSideEffect (EmitContext ec)
5523 if ((oper & Operator.LogicalMask) != 0 ||
5524 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5525 base.EmitSideEffect (ec);
5527 left.EmitSideEffect (ec);
5528 right.EmitSideEffect (ec);
5532 public override Expression EmitToField (EmitContext ec)
5534 if ((oper & Operator.LogicalMask) == 0) {
5535 var await_expr = left as Await;
5536 if (await_expr != null && right.IsSideEffectFree) {
5537 await_expr.Statement.EmitPrologue (ec);
5538 left = await_expr.Statement.GetResultExpression (ec);
5542 await_expr = right as Await;
5543 if (await_expr != null && left.IsSideEffectFree) {
5544 await_expr.Statement.EmitPrologue (ec);
5545 right = await_expr.Statement.GetResultExpression (ec);
5550 return base.EmitToField (ec);
5553 protected override void CloneTo (CloneContext clonectx, Expression t)
5555 Binary target = (Binary) t;
5557 target.left = left.Clone (clonectx);
5558 target.right = right.Clone (clonectx);
5561 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5563 Arguments binder_args = new Arguments (4);
5565 MemberAccess sle = new MemberAccess (new MemberAccess (
5566 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5568 CSharpBinderFlags flags = 0;
5569 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5570 flags = CSharpBinderFlags.CheckedContext;
5572 if ((oper & Operator.LogicalMask) != 0)
5573 flags |= CSharpBinderFlags.BinaryOperationLogical;
5575 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5576 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5577 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5578 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5580 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5583 public override Expression CreateExpressionTree (ResolveContext ec)
5585 return CreateExpressionTree (ec, null);
5588 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5591 bool lift_arg = false;
5594 case Operator.Addition:
5595 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5596 method_name = "AddChecked";
5598 method_name = "Add";
5600 case Operator.BitwiseAnd:
5601 method_name = "And";
5603 case Operator.BitwiseOr:
5606 case Operator.Division:
5607 method_name = "Divide";
5609 case Operator.Equality:
5610 method_name = "Equal";
5613 case Operator.ExclusiveOr:
5614 method_name = "ExclusiveOr";
5616 case Operator.GreaterThan:
5617 method_name = "GreaterThan";
5620 case Operator.GreaterThanOrEqual:
5621 method_name = "GreaterThanOrEqual";
5624 case Operator.Inequality:
5625 method_name = "NotEqual";
5628 case Operator.LeftShift:
5629 method_name = "LeftShift";
5631 case Operator.LessThan:
5632 method_name = "LessThan";
5635 case Operator.LessThanOrEqual:
5636 method_name = "LessThanOrEqual";
5639 case Operator.LogicalAnd:
5640 method_name = "AndAlso";
5642 case Operator.LogicalOr:
5643 method_name = "OrElse";
5645 case Operator.Modulus:
5646 method_name = "Modulo";
5648 case Operator.Multiply:
5649 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5650 method_name = "MultiplyChecked";
5652 method_name = "Multiply";
5654 case Operator.RightShift:
5655 method_name = "RightShift";
5657 case Operator.Subtraction:
5658 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5659 method_name = "SubtractChecked";
5661 method_name = "Subtract";
5665 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5668 Arguments args = new Arguments (2);
5669 args.Add (new Argument (left.CreateExpressionTree (ec)));
5670 args.Add (new Argument (right.CreateExpressionTree (ec)));
5671 if (method != null) {
5673 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5675 args.Add (new Argument (method));
5678 return CreateExpressionFactoryCall (ec, method_name, args);
5681 public override object Accept (StructuralVisitor visitor)
5683 return visitor.Visit (this);
5689 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5690 // b, c, d... may be strings or objects.
5692 public class StringConcat : Expression
5694 Arguments arguments;
5696 StringConcat (Location loc)
5699 arguments = new Arguments (2);
5702 public override bool ContainsEmitWithAwait ()
5704 return arguments.ContainsEmitWithAwait ();
5707 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5709 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5710 throw new ArgumentException ();
5712 var s = new StringConcat (loc);
5713 s.type = rc.BuiltinTypes.String;
5714 s.eclass = ExprClass.Value;
5716 s.Append (rc, left);
5717 s.Append (rc, right);
5721 public override Expression CreateExpressionTree (ResolveContext ec)
5723 Argument arg = arguments [0];
5724 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5728 // Creates nested calls tree from an array of arguments used for IL emit
5730 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5732 Arguments concat_args = new Arguments (2);
5733 Arguments add_args = new Arguments (3);
5735 concat_args.Add (left);
5736 add_args.Add (new Argument (left_etree));
5738 concat_args.Add (arguments [pos]);
5739 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5741 var methods = GetConcatMethodCandidates ();
5742 if (methods == null)
5745 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5746 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5750 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5752 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5753 if (++pos == arguments.Count)
5756 left = new Argument (new EmptyExpression (method.ReturnType));
5757 return CreateExpressionAddCall (ec, left, expr, pos);
5760 protected override Expression DoResolve (ResolveContext ec)
5765 void Append (ResolveContext rc, Expression operand)
5770 StringConstant sc = operand as StringConstant;
5772 if (arguments.Count != 0) {
5773 Argument last_argument = arguments [arguments.Count - 1];
5774 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5775 if (last_expr_constant != null) {
5776 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5782 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5784 StringConcat concat_oper = operand as StringConcat;
5785 if (concat_oper != null) {
5786 arguments.AddRange (concat_oper.arguments);
5791 arguments.Add (new Argument (operand));
5794 IList<MemberSpec> GetConcatMethodCandidates ()
5796 return MemberCache.FindMembers (type, "Concat", true);
5799 public override void Emit (EmitContext ec)
5801 // Optimize by removing any extra null arguments, they are no-op
5802 for (int i = 0; i < arguments.Count; ++i) {
5803 if (arguments[i].Expr is NullConstant)
5804 arguments.RemoveAt (i--);
5807 var members = GetConcatMethodCandidates ();
5808 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5809 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5810 if (method != null) {
5811 var call = new CallEmitter ();
5812 call.EmitPredefined (ec, method, arguments, false);
5816 public override void FlowAnalysis (FlowAnalysisContext fc)
5818 arguments.FlowAnalysis (fc);
5821 public override SLE.Expression MakeExpression (BuilderContext ctx)
5823 if (arguments.Count != 2)
5824 throw new NotImplementedException ("arguments.Count != 2");
5826 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5827 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5832 // User-defined conditional logical operator
5834 public class ConditionalLogicalOperator : UserOperatorCall
5836 readonly bool is_and;
5837 Expression oper_expr;
5839 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5840 : base (oper, arguments, expr_tree, loc)
5842 this.is_and = is_and;
5843 eclass = ExprClass.Unresolved;
5846 protected override Expression DoResolve (ResolveContext ec)
5848 AParametersCollection pd = oper.Parameters;
5849 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5850 ec.Report.Error (217, loc,
5851 "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",
5852 oper.GetSignatureForError ());
5856 Expression left_dup = new EmptyExpression (type);
5857 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5858 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5859 if (op_true == null || op_false == null) {
5860 ec.Report.Error (218, loc,
5861 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5862 type.GetSignatureForError (), oper.GetSignatureForError ());
5866 oper_expr = is_and ? op_false : op_true;
5867 eclass = ExprClass.Value;
5871 public override void Emit (EmitContext ec)
5873 Label end_target = ec.DefineLabel ();
5876 // Emit and duplicate left argument
5878 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5879 if (right_contains_await) {
5880 arguments[0] = arguments[0].EmitToField (ec, false);
5881 arguments[0].Expr.Emit (ec);
5883 arguments[0].Expr.Emit (ec);
5884 ec.Emit (OpCodes.Dup);
5885 arguments.RemoveAt (0);
5888 oper_expr.EmitBranchable (ec, end_target, true);
5892 if (right_contains_await) {
5894 // Special handling when right expression contains await and left argument
5895 // could not be left on stack before logical branch
5897 Label skip_left_load = ec.DefineLabel ();
5898 ec.Emit (OpCodes.Br_S, skip_left_load);
5899 ec.MarkLabel (end_target);
5900 arguments[0].Expr.Emit (ec);
5901 ec.MarkLabel (skip_left_load);
5903 ec.MarkLabel (end_target);
5908 public class PointerArithmetic : Expression {
5909 Expression left, right;
5910 readonly Binary.Operator op;
5913 // We assume that `l' is always a pointer
5915 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5924 public override bool ContainsEmitWithAwait ()
5926 throw new NotImplementedException ();
5929 public override Expression CreateExpressionTree (ResolveContext ec)
5931 Error_PointerInsideExpressionTree (ec);
5935 protected override Expression DoResolve (ResolveContext ec)
5937 eclass = ExprClass.Variable;
5939 var pc = left.Type as PointerContainer;
5940 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5941 Error_VoidPointerOperation (ec);
5948 public override void Emit (EmitContext ec)
5950 TypeSpec op_type = left.Type;
5952 // It must be either array or fixed buffer
5954 if (TypeManager.HasElementType (op_type)) {
5955 element = TypeManager.GetElementType (op_type);
5957 FieldExpr fe = left as FieldExpr;
5959 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5964 int size = BuiltinTypeSpec.GetSize(element);
5965 TypeSpec rtype = right.Type;
5967 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5969 // handle (pointer - pointer)
5973 ec.Emit (OpCodes.Sub);
5977 ec.Emit (OpCodes.Sizeof, element);
5980 ec.Emit (OpCodes.Div);
5982 ec.Emit (OpCodes.Conv_I8);
5985 // handle + and - on (pointer op int)
5987 Constant left_const = left as Constant;
5988 if (left_const != null) {
5990 // Optimize ((T*)null) pointer operations
5992 if (left_const.IsDefaultValue) {
5993 left = EmptyExpression.Null;
6001 var right_const = right as Constant;
6002 if (right_const != null) {
6004 // Optimize 0-based arithmetic
6006 if (right_const.IsDefaultValue)
6010 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6012 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6014 // TODO: Should be the checks resolve context sensitive?
6015 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6016 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6022 if (right_const == null) {
6023 switch (rtype.BuiltinType) {
6024 case BuiltinTypeSpec.Type.SByte:
6025 case BuiltinTypeSpec.Type.Byte:
6026 case BuiltinTypeSpec.Type.Short:
6027 case BuiltinTypeSpec.Type.UShort:
6028 case BuiltinTypeSpec.Type.Int:
6029 ec.Emit (OpCodes.Conv_I);
6031 case BuiltinTypeSpec.Type.UInt:
6032 ec.Emit (OpCodes.Conv_U);
6037 if (right_const == null && size != 1){
6039 ec.Emit (OpCodes.Sizeof, element);
6042 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6043 ec.Emit (OpCodes.Conv_I8);
6045 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6048 if (left_const == null) {
6049 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6050 ec.Emit (OpCodes.Conv_I);
6051 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6052 ec.Emit (OpCodes.Conv_U);
6054 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6061 // A boolean-expression is an expression that yields a result
6064 public class BooleanExpression : ShimExpression
6066 public BooleanExpression (Expression expr)
6069 this.loc = expr.Location;
6072 public override Expression CreateExpressionTree (ResolveContext ec)
6074 // TODO: We should emit IsTrue (v4) instead of direct user operator
6075 // call but that would break csc compatibility
6076 return base.CreateExpressionTree (ec);
6079 protected override Expression DoResolve (ResolveContext ec)
6081 // A boolean-expression is required to be of a type
6082 // that can be implicitly converted to bool or of
6083 // a type that implements operator true
6085 expr = expr.Resolve (ec);
6089 Assign ass = expr as Assign;
6090 if (ass != null && ass.Source is Constant) {
6091 ec.Report.Warning (665, 3, loc,
6092 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6095 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6098 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6099 Arguments args = new Arguments (1);
6100 args.Add (new Argument (expr));
6101 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6104 type = ec.BuiltinTypes.Bool;
6105 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6106 if (converted != null)
6110 // If no implicit conversion to bool exists, try using `operator true'
6112 converted = GetOperatorTrue (ec, expr, loc);
6113 if (converted == null) {
6114 expr.Error_ValueCannotBeConverted (ec, type, false);
6121 public override object Accept (StructuralVisitor visitor)
6123 return visitor.Visit (this);
6127 public class BooleanExpressionFalse : Unary
6129 public BooleanExpressionFalse (Expression expr)
6130 : base (Operator.LogicalNot, expr, expr.Location)
6134 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6136 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6141 /// Implements the ternary conditional operator (?:)
6143 public class Conditional : Expression {
6144 Expression expr, true_expr, false_expr;
6146 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6149 this.true_expr = true_expr;
6150 this.false_expr = false_expr;
6156 public Expression Expr {
6162 public Expression TrueExpr {
6168 public Expression FalseExpr {
6176 public override bool ContainsEmitWithAwait ()
6178 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6181 public override Expression CreateExpressionTree (ResolveContext ec)
6183 Arguments args = new Arguments (3);
6184 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6185 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6186 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6187 return CreateExpressionFactoryCall (ec, "Condition", args);
6190 protected override Expression DoResolve (ResolveContext ec)
6192 expr = expr.Resolve (ec);
6193 true_expr = true_expr.Resolve (ec);
6194 false_expr = false_expr.Resolve (ec);
6196 if (true_expr == null || false_expr == null || expr == null)
6199 eclass = ExprClass.Value;
6200 TypeSpec true_type = true_expr.Type;
6201 TypeSpec false_type = false_expr.Type;
6205 // First, if an implicit conversion exists from true_expr
6206 // to false_expr, then the result type is of type false_expr.Type
6208 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6209 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6210 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6212 // Check if both can convert implicitly to each other's type
6216 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6217 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6219 // LAMESPEC: There seems to be hardcoded promotition to int type when
6220 // both sides are numeric constants and one side is int constant and
6221 // other side is numeric constant convertible to int.
6223 // var res = condition ? (short)1 : 1;
6225 // Type of res is int even if according to the spec the conversion is
6226 // ambiguous because 1 literal can be converted to short.
6228 if (conv_false_expr != null) {
6229 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6231 conv_false_expr = null;
6232 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6233 conv_false_expr = null;
6237 if (conv_false_expr != null) {
6238 ec.Report.Error (172, true_expr.Location,
6239 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6240 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6245 if (true_expr.Type != type)
6246 true_expr = EmptyCast.Create (true_expr, type);
6247 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6250 if (false_type != InternalType.ErrorType) {
6251 ec.Report.Error (173, true_expr.Location,
6252 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6253 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6259 Constant c = expr as Constant;
6261 bool is_false = c.IsDefaultValue;
6264 // Don't issue the warning for constant expressions
6266 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6267 // CSC: Missing warning
6268 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6271 return ReducedExpression.Create (
6272 is_false ? false_expr : true_expr, this,
6273 false_expr is Constant && true_expr is Constant).Resolve (ec);
6279 public override void Emit (EmitContext ec)
6281 Label false_target = ec.DefineLabel ();
6282 Label end_target = ec.DefineLabel ();
6284 expr.EmitBranchable (ec, false_target, false);
6285 true_expr.Emit (ec);
6288 // Verifier doesn't support interface merging. When there are two types on
6289 // the stack without common type hint and the common type is an interface.
6290 // Use temporary local to give verifier hint on what type to unify the stack
6292 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6293 var temp = ec.GetTemporaryLocal (type);
6294 ec.Emit (OpCodes.Stloc, temp);
6295 ec.Emit (OpCodes.Ldloc, temp);
6296 ec.FreeTemporaryLocal (temp, type);
6299 ec.Emit (OpCodes.Br, end_target);
6300 ec.MarkLabel (false_target);
6301 false_expr.Emit (ec);
6302 ec.MarkLabel (end_target);
6305 public override void FlowAnalysis (FlowAnalysisContext fc)
6307 expr.FlowAnalysisConditional (fc);
6308 var expr_true = fc.DefiniteAssignmentOnTrue;
6309 var expr_false = fc.DefiniteAssignmentOnFalse;
6311 fc.BranchDefiniteAssignment (expr_true);
6312 true_expr.FlowAnalysis (fc);
6313 var true_fc = fc.DefiniteAssignment;
6315 fc.BranchDefiniteAssignment (expr_false);
6316 false_expr.FlowAnalysis (fc);
6318 fc.DefiniteAssignment &= true_fc;
6321 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6323 expr.FlowAnalysisConditional (fc);
6324 var expr_true = fc.DefiniteAssignmentOnTrue;
6325 var expr_false = fc.DefiniteAssignmentOnFalse;
6327 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6328 true_expr.FlowAnalysisConditional (fc);
6329 var true_fc = fc.DefiniteAssignment;
6330 var true_da_true = fc.DefiniteAssignmentOnTrue;
6331 var true_da_false = fc.DefiniteAssignmentOnFalse;
6333 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6334 false_expr.FlowAnalysisConditional (fc);
6336 fc.DefiniteAssignment &= true_fc;
6337 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6338 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6341 protected override void CloneTo (CloneContext clonectx, Expression t)
6343 Conditional target = (Conditional) t;
6345 target.expr = expr.Clone (clonectx);
6346 target.true_expr = true_expr.Clone (clonectx);
6347 target.false_expr = false_expr.Clone (clonectx);
6351 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6353 LocalTemporary temp;
6356 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6357 public abstract void SetHasAddressTaken ();
6359 public abstract bool IsLockedByStatement { get; set; }
6361 public abstract bool IsFixed { get; }
6362 public abstract bool IsRef { get; }
6363 public abstract string Name { get; }
6366 // Variable IL data, it has to be protected to encapsulate hoisted variables
6368 protected abstract ILocalVariable Variable { get; }
6371 // Variable flow-analysis data
6373 public abstract VariableInfo VariableInfo { get; }
6376 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6378 HoistedVariable hv = GetHoistedVariable (ec);
6380 hv.AddressOf (ec, mode);
6384 Variable.EmitAddressOf (ec);
6387 public override bool ContainsEmitWithAwait ()
6392 public override Expression CreateExpressionTree (ResolveContext ec)
6394 HoistedVariable hv = GetHoistedVariable (ec);
6396 return hv.CreateExpressionTree ();
6398 Arguments arg = new Arguments (1);
6399 arg.Add (new Argument (this));
6400 return CreateExpressionFactoryCall (ec, "Constant", arg);
6403 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6405 if (IsLockedByStatement) {
6406 rc.Report.Warning (728, 2, loc,
6407 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6414 public override void Emit (EmitContext ec)
6419 public override void EmitSideEffect (EmitContext ec)
6425 // This method is used by parameters that are references, that are
6426 // being passed as references: we only want to pass the pointer (that
6427 // is already stored in the parameter, not the address of the pointer,
6428 // and not the value of the variable).
6430 public void EmitLoad (EmitContext ec)
6435 public void Emit (EmitContext ec, bool leave_copy)
6437 HoistedVariable hv = GetHoistedVariable (ec);
6439 hv.Emit (ec, leave_copy);
6447 // If we are a reference, we loaded on the stack a pointer
6448 // Now lets load the real value
6450 ec.EmitLoadFromPtr (type);
6454 ec.Emit (OpCodes.Dup);
6457 temp = new LocalTemporary (Type);
6463 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6464 bool prepare_for_load)
6466 HoistedVariable hv = GetHoistedVariable (ec);
6468 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6472 New n_source = source as New;
6473 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6474 if (!n_source.Emit (ec, this)) {
6478 ec.EmitLoadFromPtr (type);
6490 ec.Emit (OpCodes.Dup);
6492 temp = new LocalTemporary (Type);
6498 ec.EmitStoreFromPtr (type);
6500 Variable.EmitAssign (ec);
6508 public override Expression EmitToField (EmitContext ec)
6510 HoistedVariable hv = GetHoistedVariable (ec);
6512 return hv.EmitToField (ec);
6515 return base.EmitToField (ec);
6518 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6520 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6523 public HoistedVariable GetHoistedVariable (EmitContext ec)
6525 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6528 public override string GetSignatureForError ()
6533 public bool IsHoisted {
6534 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6539 // Resolved reference to a local variable
6541 public class LocalVariableReference : VariableReference
6543 public LocalVariable local_info;
6545 public LocalVariableReference (LocalVariable li, Location l)
6547 this.local_info = li;
6551 public override VariableInfo VariableInfo {
6552 get { return local_info.VariableInfo; }
6555 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6557 return local_info.HoistedVariant;
6563 // A local variable is always fixed
6565 public override bool IsFixed {
6571 public override bool IsLockedByStatement {
6573 return local_info.IsLocked;
6576 local_info.IsLocked = value;
6580 public override bool IsRef {
6581 get { return false; }
6584 public override string Name {
6585 get { return local_info.Name; }
6590 public override void FlowAnalysis (FlowAnalysisContext fc)
6592 VariableInfo variable_info = VariableInfo;
6593 if (variable_info == null)
6596 if (fc.IsDefinitelyAssigned (variable_info))
6599 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6600 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6603 public override void SetHasAddressTaken ()
6605 local_info.SetHasAddressTaken ();
6608 void DoResolveBase (ResolveContext ec)
6610 eclass = ExprClass.Variable;
6611 type = local_info.Type;
6614 // If we are referencing a variable from the external block
6615 // flag it for capturing
6617 if (ec.MustCaptureVariable (local_info)) {
6618 if (local_info.AddressTaken) {
6619 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6620 } else if (local_info.IsFixed) {
6621 ec.Report.Error (1764, loc,
6622 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6623 GetSignatureForError ());
6626 if (ec.IsVariableCapturingRequired) {
6627 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6628 storey.CaptureLocalVariable (ec, local_info);
6633 protected override Expression DoResolve (ResolveContext ec)
6635 local_info.SetIsUsed ();
6639 if (local_info.Type == InternalType.VarOutType) {
6640 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6641 GetSignatureForError ());
6643 type = InternalType.ErrorType;
6649 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6652 // Don't be too pedantic when variable is used as out param or for some broken code
6653 // which uses property/indexer access to run some initialization
6655 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6656 local_info.SetIsUsed ();
6658 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6659 if (rhs == EmptyExpression.LValueMemberAccess) {
6660 // CS1654 already reported
6664 if (rhs == EmptyExpression.OutAccess) {
6665 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6666 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6667 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6668 } else if (rhs == EmptyExpression.UnaryAddress) {
6669 code = 459; msg = "Cannot take the address of {1} `{0}'";
6671 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6673 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6677 if (eclass == ExprClass.Unresolved)
6680 return base.DoResolveLValue (ec, rhs);
6683 public override int GetHashCode ()
6685 return local_info.GetHashCode ();
6688 public override bool Equals (object obj)
6690 LocalVariableReference lvr = obj as LocalVariableReference;
6694 return local_info == lvr.local_info;
6697 protected override ILocalVariable Variable {
6698 get { return local_info; }
6701 public override string ToString ()
6703 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6706 protected override void CloneTo (CloneContext clonectx, Expression t)
6713 /// This represents a reference to a parameter in the intermediate
6716 public class ParameterReference : VariableReference
6718 protected ParametersBlock.ParameterInfo pi;
6720 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6728 public override bool IsLockedByStatement {
6733 pi.IsLocked = value;
6737 public override bool IsRef {
6738 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6741 bool HasOutModifier {
6742 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6745 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6747 return pi.Parameter.HoistedVariant;
6751 // A ref or out parameter is classified as a moveable variable, even
6752 // if the argument given for the parameter is a fixed variable
6754 public override bool IsFixed {
6755 get { return !IsRef; }
6758 public override string Name {
6759 get { return Parameter.Name; }
6762 public Parameter Parameter {
6763 get { return pi.Parameter; }
6766 public override VariableInfo VariableInfo {
6767 get { return pi.VariableInfo; }
6770 protected override ILocalVariable Variable {
6771 get { return Parameter; }
6776 public override void AddressOf (EmitContext ec, AddressOp mode)
6779 // ParameterReferences might already be a reference
6786 base.AddressOf (ec, mode);
6789 public override void SetHasAddressTaken ()
6791 Parameter.HasAddressTaken = true;
6794 bool DoResolveBase (ResolveContext ec)
6796 if (eclass != ExprClass.Unresolved)
6799 type = pi.ParameterType;
6800 eclass = ExprClass.Variable;
6803 // If we are referencing a parameter from the external block
6804 // flag it for capturing
6806 if (ec.MustCaptureVariable (pi)) {
6807 if (Parameter.HasAddressTaken)
6808 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6811 ec.Report.Error (1628, loc,
6812 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6813 Name, ec.CurrentAnonymousMethod.ContainerType);
6816 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6817 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6818 storey.CaptureParameter (ec, pi, this);
6825 public override int GetHashCode ()
6827 return Name.GetHashCode ();
6830 public override bool Equals (object obj)
6832 ParameterReference pr = obj as ParameterReference;
6836 return Name == pr.Name;
6839 protected override void CloneTo (CloneContext clonectx, Expression target)
6845 public override Expression CreateExpressionTree (ResolveContext ec)
6847 HoistedVariable hv = GetHoistedVariable (ec);
6849 return hv.CreateExpressionTree ();
6851 return Parameter.ExpressionTreeVariableReference ();
6854 protected override Expression DoResolve (ResolveContext ec)
6856 if (!DoResolveBase (ec))
6862 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6864 if (!DoResolveBase (ec))
6867 if (Parameter.HoistedVariant != null)
6868 Parameter.HoistedVariant.IsAssigned = true;
6870 return base.DoResolveLValue (ec, right_side);
6873 public override void FlowAnalysis (FlowAnalysisContext fc)
6875 VariableInfo variable_info = VariableInfo;
6876 if (variable_info == null)
6879 if (fc.IsDefinitelyAssigned (variable_info))
6882 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6883 fc.SetVariableAssigned (variable_info);
6888 /// Invocation of methods or delegates.
6890 public class Invocation : ExpressionStatement
6892 public class Predefined : Invocation
6894 public Predefined (MethodGroupExpr expr, Arguments arguments)
6895 : base (expr, arguments)
6900 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6902 mg.BestCandidate.CheckObsoleteness (rc, loc);
6908 protected Arguments arguments;
6909 protected Expression expr;
6910 protected MethodGroupExpr mg;
6911 bool conditional_access_receiver;
6913 public Invocation (Expression expr, Arguments arguments)
6916 this.arguments = arguments;
6918 loc = expr.Location;
6923 public Arguments Arguments {
6929 public Expression Exp {
6935 public MethodGroupExpr MethodGroup {
6941 public override Location StartLocation {
6943 return expr.StartLocation;
6949 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6951 if (MethodGroup == null)
6954 var candidate = MethodGroup.BestCandidate;
6955 if (candidate == null || !(candidate.IsStatic || Exp is This))
6958 var args_count = arguments == null ? 0 : arguments.Count;
6959 if (args_count != body.Parameters.Count)
6962 var lambda_parameters = body.Block.Parameters.FixedParameters;
6963 for (int i = 0; i < args_count; ++i) {
6964 var pr = arguments[i].Expr as ParameterReference;
6968 if (lambda_parameters[i] != pr.Parameter)
6971 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6975 var emg = MethodGroup as ExtensionMethodGroupExpr;
6977 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6978 if (candidate.IsGeneric) {
6979 var targs = new TypeExpression [candidate.Arity];
6980 for (int i = 0; i < targs.Length; ++i) {
6981 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6984 mg.SetTypeArguments (null, new TypeArguments (targs));
6993 protected override void CloneTo (CloneContext clonectx, Expression t)
6995 Invocation target = (Invocation) t;
6997 if (arguments != null)
6998 target.arguments = arguments.Clone (clonectx);
7000 target.expr = expr.Clone (clonectx);
7003 public override bool ContainsEmitWithAwait ()
7005 if (arguments != null && arguments.ContainsEmitWithAwait ())
7008 return mg.ContainsEmitWithAwait ();
7011 public override Expression CreateExpressionTree (ResolveContext ec)
7013 Expression instance = mg.IsInstance ?
7014 mg.InstanceExpression.CreateExpressionTree (ec) :
7015 new NullLiteral (loc);
7017 var args = Arguments.CreateForExpressionTree (ec, arguments,
7019 mg.CreateExpressionTree (ec));
7021 return CreateExpressionFactoryCall (ec, "Call", args);
7024 void ResolveConditionalAccessReceiver (ResolveContext rc)
7026 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7027 conditional_access_receiver = true;
7031 bool statement_resolve;
7032 public override ExpressionStatement ResolveStatement (BlockContext bc)
7034 statement_resolve = true;
7035 var es = base.ResolveStatement (bc);
7036 statement_resolve = false;
7041 protected override Expression DoResolve (ResolveContext rc)
7043 ResolveConditionalAccessReceiver (rc);
7044 return DoResolveInvocation (rc);
7047 Expression DoResolveInvocation (ResolveContext ec)
7049 Expression member_expr;
7050 var atn = expr as ATypeNameExpression;
7052 var flags = default (ResolveContext.FlagsHandle);
7053 if (conditional_access_receiver)
7054 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7057 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7058 if (member_expr != null) {
7059 var name_of = member_expr as NameOf;
7060 if (name_of != null) {
7061 return name_of.ResolveOverload (ec, arguments);
7064 member_expr = member_expr.Resolve (ec);
7067 member_expr = expr.Resolve (ec);
7070 if (conditional_access_receiver)
7073 if (member_expr == null)
7077 // Next, evaluate all the expressions in the argument list
7079 bool dynamic_arg = false;
7080 if (arguments != null) {
7081 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7082 arguments.Resolve (ec, out dynamic_arg);
7086 TypeSpec expr_type = member_expr.Type;
7087 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7088 return DoResolveDynamic (ec, member_expr);
7090 mg = member_expr as MethodGroupExpr;
7091 Expression invoke = null;
7094 if (expr_type != null && expr_type.IsDelegate) {
7095 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7096 invoke = invoke.Resolve (ec);
7097 if (invoke == null || !dynamic_arg)
7100 if (member_expr is RuntimeValueExpression) {
7101 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7102 member_expr.Type.GetSignatureForError ());
7106 MemberExpr me = member_expr as MemberExpr;
7108 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7112 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7113 member_expr.GetSignatureForError ());
7118 if (invoke == null) {
7119 mg = DoResolveOverload (ec);
7125 return DoResolveDynamic (ec, member_expr);
7127 var method = mg.BestCandidate;
7128 type = mg.BestCandidateReturnType;
7129 if (conditional_access_receiver && !statement_resolve)
7130 type = LiftMemberType (ec, type);
7132 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7134 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7136 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7140 IsSpecialMethodInvocation (ec, method, loc);
7142 eclass = ExprClass.Value;
7146 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7149 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7151 args = dmb.Arguments;
7152 if (arguments != null)
7153 args.AddRange (arguments);
7154 } else if (mg == null) {
7155 if (arguments == null)
7156 args = new Arguments (1);
7160 args.Insert (0, new Argument (memberExpr));
7164 ec.Report.Error (1971, loc,
7165 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7170 if (arguments == null)
7171 args = new Arguments (1);
7175 MemberAccess ma = expr as MemberAccess;
7177 var inst = mg.InstanceExpression;
7178 var left_type = inst as TypeExpr;
7179 if (left_type != null) {
7180 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7181 } else if (inst != null) {
7183 // Any value type has to be pass as by-ref to get back the same
7184 // instance on which the member was called
7186 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7187 Argument.AType.Ref : Argument.AType.None;
7188 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7190 } else { // is SimpleName
7191 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7192 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7194 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7199 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7202 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7204 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7207 public override void FlowAnalysis (FlowAnalysisContext fc)
7209 if (mg.IsConditionallyExcluded)
7212 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7214 mg.FlowAnalysis (fc);
7216 if (arguments != null)
7217 arguments.FlowAnalysis (fc);
7219 if (conditional_access_receiver)
7220 fc.DefiniteAssignment = da;
7223 public override string GetSignatureForError ()
7225 return mg.GetSignatureForError ();
7228 public override bool HasConditionalAccess ()
7230 return expr.HasConditionalAccess ();
7234 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7235 // or the type dynamic, then the member is invocable
7237 public static bool IsMemberInvocable (MemberSpec member)
7239 switch (member.Kind) {
7240 case MemberKind.Event:
7242 case MemberKind.Field:
7243 case MemberKind.Property:
7244 var m = member as IInterfaceMemberSpec;
7245 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7251 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7253 if (!method.IsReservedMethod)
7256 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7259 ec.Report.SymbolRelatedToPreviousError (method);
7260 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7261 method.GetSignatureForError ());
7266 public override void Emit (EmitContext ec)
7268 if (mg.IsConditionallyExcluded)
7271 if (conditional_access_receiver)
7272 mg.EmitCall (ec, arguments, type, false);
7274 mg.EmitCall (ec, arguments, false);
7277 public override void EmitStatement (EmitContext ec)
7279 if (mg.IsConditionallyExcluded)
7282 if (conditional_access_receiver)
7283 mg.EmitCall (ec, arguments, type, true);
7285 mg.EmitCall (ec, arguments, true);
7288 public override SLE.Expression MakeExpression (BuilderContext ctx)
7290 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7293 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7296 throw new NotSupportedException ();
7298 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7299 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7303 public override object Accept (StructuralVisitor visitor)
7305 return visitor.Visit (this);
7310 // Implements simple new expression
7312 public class New : ExpressionStatement, IMemoryLocation
7314 protected Arguments arguments;
7317 // During bootstrap, it contains the RequestedType,
7318 // but if `type' is not null, it *might* contain a NewDelegate
7319 // (because of field multi-initialization)
7321 protected Expression RequestedType;
7323 protected MethodSpec method;
7325 public New (Expression requested_type, Arguments arguments, Location l)
7327 RequestedType = requested_type;
7328 this.arguments = arguments;
7333 public Arguments Arguments {
7340 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7342 public bool IsGeneratedStructConstructor {
7344 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7348 public Expression TypeExpression {
7350 return RequestedType;
7357 /// Converts complex core type syntax like 'new int ()' to simple constant
7359 public static Constant Constantify (TypeSpec t, Location loc)
7361 switch (t.BuiltinType) {
7362 case BuiltinTypeSpec.Type.Int:
7363 return new IntConstant (t, 0, loc);
7364 case BuiltinTypeSpec.Type.UInt:
7365 return new UIntConstant (t, 0, loc);
7366 case BuiltinTypeSpec.Type.Long:
7367 return new LongConstant (t, 0, loc);
7368 case BuiltinTypeSpec.Type.ULong:
7369 return new ULongConstant (t, 0, loc);
7370 case BuiltinTypeSpec.Type.Float:
7371 return new FloatConstant (t, 0, loc);
7372 case BuiltinTypeSpec.Type.Double:
7373 return new DoubleConstant (t, 0, loc);
7374 case BuiltinTypeSpec.Type.Short:
7375 return new ShortConstant (t, 0, loc);
7376 case BuiltinTypeSpec.Type.UShort:
7377 return new UShortConstant (t, 0, loc);
7378 case BuiltinTypeSpec.Type.SByte:
7379 return new SByteConstant (t, 0, loc);
7380 case BuiltinTypeSpec.Type.Byte:
7381 return new ByteConstant (t, 0, loc);
7382 case BuiltinTypeSpec.Type.Char:
7383 return new CharConstant (t, '\0', loc);
7384 case BuiltinTypeSpec.Type.Bool:
7385 return new BoolConstant (t, false, loc);
7386 case BuiltinTypeSpec.Type.Decimal:
7387 return new DecimalConstant (t, 0, loc);
7391 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7393 if (t.IsNullableType)
7394 return Nullable.LiftedNull.Create (t, loc);
7399 public override bool ContainsEmitWithAwait ()
7401 return arguments != null && arguments.ContainsEmitWithAwait ();
7405 // Checks whether the type is an interface that has the
7406 // [ComImport, CoClass] attributes and must be treated
7409 public Expression CheckComImport (ResolveContext ec)
7411 if (!type.IsInterface)
7415 // Turn the call into:
7416 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7418 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7419 if (real_class == null)
7422 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7423 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7424 return cast.Resolve (ec);
7427 public override Expression CreateExpressionTree (ResolveContext ec)
7430 if (method == null) {
7431 args = new Arguments (1);
7432 args.Add (new Argument (new TypeOf (type, loc)));
7434 args = Arguments.CreateForExpressionTree (ec,
7435 arguments, new TypeOfMethod (method, loc));
7438 return CreateExpressionFactoryCall (ec, "New", args);
7441 protected override Expression DoResolve (ResolveContext ec)
7443 type = RequestedType.ResolveAsType (ec);
7447 eclass = ExprClass.Value;
7449 if (type.IsPointer) {
7450 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7451 type.GetSignatureForError ());
7455 if (arguments == null) {
7456 Constant c = Constantify (type, RequestedType.Location);
7458 return ReducedExpression.Create (c, this);
7461 if (type.IsDelegate) {
7462 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7465 var tparam = type as TypeParameterSpec;
7466 if (tparam != null) {
7468 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7469 // where type parameter constraint is inflated to struct
7471 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7472 ec.Report.Error (304, loc,
7473 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7474 type.GetSignatureForError ());
7477 if ((arguments != null) && (arguments.Count != 0)) {
7478 ec.Report.Error (417, loc,
7479 "`{0}': cannot provide arguments when creating an instance of a variable type",
7480 type.GetSignatureForError ());
7486 if (type.IsStatic) {
7487 ec.Report.SymbolRelatedToPreviousError (type);
7488 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7492 if (type.IsInterface || type.IsAbstract){
7493 if (!TypeManager.IsGenericType (type)) {
7494 RequestedType = CheckComImport (ec);
7495 if (RequestedType != null)
7496 return RequestedType;
7499 ec.Report.SymbolRelatedToPreviousError (type);
7500 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7505 if (arguments != null) {
7506 arguments.Resolve (ec, out dynamic);
7511 method = ConstructorLookup (ec, type, ref arguments, loc);
7514 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7515 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7521 void DoEmitTypeParameter (EmitContext ec)
7523 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7527 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7528 ec.Emit (OpCodes.Call, ctor_factory);
7532 // This Emit can be invoked in two contexts:
7533 // * As a mechanism that will leave a value on the stack (new object)
7534 // * As one that wont (init struct)
7536 // If we are dealing with a ValueType, we have a few
7537 // situations to deal with:
7539 // * The target is a ValueType, and we have been provided
7540 // the instance (this is easy, we are being assigned).
7542 // * The target of New is being passed as an argument,
7543 // to a boxing operation or a function that takes a
7546 // In this case, we need to create a temporary variable
7547 // that is the argument of New.
7549 // Returns whether a value is left on the stack
7551 // *** Implementation note ***
7553 // To benefit from this optimization, each assignable expression
7554 // has to manually cast to New and call this Emit.
7556 // TODO: It's worth to implement it for arrays and fields
7558 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7560 bool is_value_type = type.IsStructOrEnum;
7561 VariableReference vr = target as VariableReference;
7563 if (target != null && is_value_type && (vr != null || method == null)) {
7564 target.AddressOf (ec, AddressOp.Store);
7565 } else if (vr != null && vr.IsRef) {
7569 if (arguments != null) {
7570 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7571 arguments = arguments.Emit (ec, false, true);
7573 arguments.Emit (ec);
7576 if (is_value_type) {
7577 if (method == null) {
7578 ec.Emit (OpCodes.Initobj, type);
7583 ec.MarkCallEntry (loc);
7584 ec.Emit (OpCodes.Call, method);
7589 if (type is TypeParameterSpec) {
7590 DoEmitTypeParameter (ec);
7594 ec.MarkCallEntry (loc);
7595 ec.Emit (OpCodes.Newobj, method);
7599 public override void Emit (EmitContext ec)
7601 LocalTemporary v = null;
7602 if (method == null && type.IsStructOrEnum) {
7603 // TODO: Use temporary variable from pool
7604 v = new LocalTemporary (type);
7611 public override void EmitStatement (EmitContext ec)
7613 LocalTemporary v = null;
7614 if (method == null && TypeSpec.IsValueType (type)) {
7615 // TODO: Use temporary variable from pool
7616 v = new LocalTemporary (type);
7620 ec.Emit (OpCodes.Pop);
7623 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7628 public override void FlowAnalysis (FlowAnalysisContext fc)
7630 if (arguments != null)
7631 arguments.FlowAnalysis (fc);
7634 public void AddressOf (EmitContext ec, AddressOp mode)
7636 EmitAddressOf (ec, mode);
7639 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7641 LocalTemporary value_target = new LocalTemporary (type);
7643 if (type is TypeParameterSpec) {
7644 DoEmitTypeParameter (ec);
7645 value_target.Store (ec);
7646 value_target.AddressOf (ec, mode);
7647 return value_target;
7650 value_target.AddressOf (ec, AddressOp.Store);
7652 if (method == null) {
7653 ec.Emit (OpCodes.Initobj, type);
7655 if (arguments != null)
7656 arguments.Emit (ec);
7658 ec.Emit (OpCodes.Call, method);
7661 value_target.AddressOf (ec, mode);
7662 return value_target;
7665 protected override void CloneTo (CloneContext clonectx, Expression t)
7667 New target = (New) t;
7669 target.RequestedType = RequestedType.Clone (clonectx);
7670 if (arguments != null){
7671 target.arguments = arguments.Clone (clonectx);
7675 public override SLE.Expression MakeExpression (BuilderContext ctx)
7678 return base.MakeExpression (ctx);
7680 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7684 public override object Accept (StructuralVisitor visitor)
7686 return visitor.Visit (this);
7691 // Array initializer expression, the expression is allowed in
7692 // variable or field initialization only which makes it tricky as
7693 // the type has to be infered based on the context either from field
7694 // type or variable type (think of multiple declarators)
7696 public class ArrayInitializer : Expression
7698 List<Expression> elements;
7699 BlockVariable variable;
7701 public ArrayInitializer (List<Expression> init, Location loc)
7707 public ArrayInitializer (int count, Location loc)
7708 : this (new List<Expression> (count), loc)
7712 public ArrayInitializer (Location loc)
7720 get { return elements.Count; }
7723 public List<Expression> Elements {
7729 public Expression this [int index] {
7731 return elements [index];
7735 public BlockVariable VariableDeclaration {
7746 public void Add (Expression expr)
7748 elements.Add (expr);
7751 public override bool ContainsEmitWithAwait ()
7753 throw new NotSupportedException ();
7756 public override Expression CreateExpressionTree (ResolveContext ec)
7758 throw new NotSupportedException ("ET");
7761 protected override void CloneTo (CloneContext clonectx, Expression t)
7763 var target = (ArrayInitializer) t;
7765 target.elements = new List<Expression> (elements.Count);
7766 foreach (var element in elements)
7767 target.elements.Add (element.Clone (clonectx));
7770 protected override Expression DoResolve (ResolveContext rc)
7772 var current_field = rc.CurrentMemberDefinition as FieldBase;
7773 TypeExpression type;
7774 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7775 type = new TypeExpression (current_field.MemberType, current_field.Location);
7776 } else if (variable != null) {
7777 if (variable.TypeExpression is VarExpr) {
7778 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7779 return EmptyExpression.Null;
7782 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7784 throw new NotImplementedException ("Unexpected array initializer context");
7787 return new ArrayCreation (type, this).Resolve (rc);
7790 public override void Emit (EmitContext ec)
7792 throw new InternalErrorException ("Missing Resolve call");
7795 public override void FlowAnalysis (FlowAnalysisContext fc)
7797 throw new InternalErrorException ("Missing Resolve call");
7800 public override object Accept (StructuralVisitor visitor)
7802 return visitor.Visit (this);
7807 /// 14.5.10.2: Represents an array creation expression.
7811 /// There are two possible scenarios here: one is an array creation
7812 /// expression that specifies the dimensions and optionally the
7813 /// initialization data and the other which does not need dimensions
7814 /// specified but where initialization data is mandatory.
7816 public class ArrayCreation : Expression
7818 FullNamedExpression requested_base_type;
7819 ArrayInitializer initializers;
7822 // The list of Argument types.
7823 // This is used to construct the `newarray' or constructor signature
7825 protected List<Expression> arguments;
7827 protected TypeSpec array_element_type;
7829 protected int dimensions;
7830 protected readonly ComposedTypeSpecifier rank;
7831 Expression first_emit;
7832 LocalTemporary first_emit_temp;
7834 protected List<Expression> array_data;
7836 Dictionary<int, int> bounds;
7839 // The number of constants in array initializers
7840 int const_initializers_count;
7841 bool only_constant_initializers;
7843 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7844 : this (requested_base_type, rank, initializers, l)
7846 arguments = new List<Expression> (exprs);
7847 num_arguments = arguments.Count;
7851 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7853 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7855 this.requested_base_type = requested_base_type;
7857 this.initializers = initializers;
7861 num_arguments = rank.Dimension;
7865 // For compiler generated single dimensional arrays only
7867 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7868 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7873 // For expressions like int[] foo = { 1, 2, 3 };
7875 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7876 : this (requested_base_type, null, initializers, initializers.Location)
7880 public bool NoEmptyInterpolation { get; set; }
7882 public ComposedTypeSpecifier Rank {
7888 public FullNamedExpression TypeExpression {
7890 return this.requested_base_type;
7894 public ArrayInitializer Initializers {
7896 return this.initializers;
7900 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7902 if (initializers != null && bounds == null) {
7904 // We use this to store all the data values in the order in which we
7905 // will need to store them in the byte blob later
7907 array_data = new List<Expression> (probe.Count);
7908 bounds = new Dictionary<int, int> ();
7911 if (specified_dims) {
7912 Expression a = arguments [idx];
7917 a = ConvertExpressionToArrayIndex (ec, a);
7923 if (initializers != null) {
7924 Constant c = a as Constant;
7925 if (c == null && a is ArrayIndexCast)
7926 c = ((ArrayIndexCast) a).Child as Constant;
7929 ec.Report.Error (150, a.Location, "A constant value is expected");
7935 value = System.Convert.ToInt32 (c.GetValue ());
7937 ec.Report.Error (150, a.Location, "A constant value is expected");
7941 // TODO: probe.Count does not fit ulong in
7942 if (value != probe.Count) {
7943 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7947 bounds[idx] = value;
7951 if (initializers == null)
7954 for (int i = 0; i < probe.Count; ++i) {
7956 if (o is ArrayInitializer) {
7957 var sub_probe = o as ArrayInitializer;
7958 if (idx + 1 >= dimensions){
7959 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7963 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7964 if (!bounds.ContainsKey(idx + 1))
7965 bounds[idx + 1] = sub_probe.Count;
7967 if (bounds[idx + 1] != sub_probe.Count) {
7968 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7972 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7975 } else if (child_bounds > 1) {
7976 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7978 Expression element = ResolveArrayElement (ec, o);
7979 if (element == null)
7982 // Initializers with the default values can be ignored
7983 Constant c = element as Constant;
7985 if (!c.IsDefaultInitializer (array_element_type)) {
7986 ++const_initializers_count;
7989 only_constant_initializers = false;
7992 array_data.Add (element);
7999 public override bool ContainsEmitWithAwait ()
8001 foreach (var arg in arguments) {
8002 if (arg.ContainsEmitWithAwait ())
8006 return InitializersContainAwait ();
8009 public override Expression CreateExpressionTree (ResolveContext ec)
8013 if (array_data == null) {
8014 args = new Arguments (arguments.Count + 1);
8015 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8016 foreach (Expression a in arguments)
8017 args.Add (new Argument (a.CreateExpressionTree (ec)));
8019 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8022 if (dimensions > 1) {
8023 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8027 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8028 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8029 if (array_data != null) {
8030 for (int i = 0; i < array_data.Count; ++i) {
8031 Expression e = array_data [i];
8032 args.Add (new Argument (e.CreateExpressionTree (ec)));
8036 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8039 void UpdateIndices (ResolveContext rc)
8042 for (var probe = initializers; probe != null;) {
8043 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8045 bounds[i++] = probe.Count;
8047 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8048 probe = (ArrayInitializer) probe[0];
8049 } else if (dimensions > i) {
8057 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8059 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8062 public override void FlowAnalysis (FlowAnalysisContext fc)
8064 foreach (var arg in arguments)
8065 arg.FlowAnalysis (fc);
8067 if (array_data != null) {
8068 foreach (var ad in array_data)
8069 ad.FlowAnalysis (fc);
8073 bool InitializersContainAwait ()
8075 if (array_data == null)
8078 foreach (var expr in array_data) {
8079 if (expr.ContainsEmitWithAwait ())
8086 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8088 element = element.Resolve (ec);
8089 if (element == null)
8092 var te = element as CompoundAssign.TargetExpression;
8094 for (int i = 1; i < initializers.Count; ++i) {
8095 if (initializers [i].ContainsEmitWithAwait ()) {
8096 te.RequiresEmitWithAwait = true;
8101 if (!te.RequiresEmitWithAwait) {
8102 if (first_emit != null)
8103 throw new InternalErrorException ("Can only handle one mutator at a time");
8104 first_emit = element;
8105 element = first_emit_temp = new LocalTemporary (element.Type);
8109 return Convert.ImplicitConversionRequired (
8110 ec, element, array_element_type, loc);
8113 protected bool ResolveInitializers (ResolveContext ec)
8116 only_constant_initializers = true;
8119 if (arguments != null) {
8121 for (int i = 0; i < arguments.Count; ++i) {
8122 res &= CheckIndices (ec, initializers, i, true, dimensions);
8123 if (initializers != null)
8130 arguments = new List<Expression> ();
8132 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8141 // Resolved the type of the array
8143 bool ResolveArrayType (ResolveContext ec)
8148 FullNamedExpression array_type_expr;
8149 if (num_arguments > 0) {
8150 array_type_expr = new ComposedCast (requested_base_type, rank);
8152 array_type_expr = requested_base_type;
8155 type = array_type_expr.ResolveAsType (ec);
8156 if (array_type_expr == null)
8159 var ac = type as ArrayContainer;
8161 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8165 array_element_type = ac.Element;
8166 dimensions = ac.Rank;
8171 protected override Expression DoResolve (ResolveContext ec)
8176 if (!ResolveArrayType (ec))
8180 // validate the initializers and fill in any missing bits
8182 if (!ResolveInitializers (ec))
8185 eclass = ExprClass.Value;
8189 byte [] MakeByteBlob ()
8194 int count = array_data.Count;
8196 TypeSpec element_type = array_element_type;
8197 if (element_type.IsEnum)
8198 element_type = EnumSpec.GetUnderlyingType (element_type);
8200 factor = BuiltinTypeSpec.GetSize (element_type);
8202 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8204 data = new byte [(count * factor + 3) & ~3];
8207 for (int i = 0; i < count; ++i) {
8208 var c = array_data[i] as Constant;
8214 object v = c.GetValue ();
8216 switch (element_type.BuiltinType) {
8217 case BuiltinTypeSpec.Type.Long:
8218 long lval = (long) v;
8220 for (int j = 0; j < factor; ++j) {
8221 data[idx + j] = (byte) (lval & 0xFF);
8225 case BuiltinTypeSpec.Type.ULong:
8226 ulong ulval = (ulong) v;
8228 for (int j = 0; j < factor; ++j) {
8229 data[idx + j] = (byte) (ulval & 0xFF);
8230 ulval = (ulval >> 8);
8233 case BuiltinTypeSpec.Type.Float:
8234 var fval = SingleConverter.SingleToInt32Bits((float) v);
8236 data[idx] = (byte) (fval & 0xff);
8237 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8238 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8239 data[idx + 3] = (byte) (fval >> 24);
8241 case BuiltinTypeSpec.Type.Double:
8242 element = BitConverter.GetBytes ((double) v);
8244 for (int j = 0; j < factor; ++j)
8245 data[idx + j] = element[j];
8247 // FIXME: Handle the ARM float format.
8248 if (!BitConverter.IsLittleEndian)
8249 System.Array.Reverse (data, idx, 8);
8251 case BuiltinTypeSpec.Type.Char:
8252 int chval = (int) ((char) v);
8254 data[idx] = (byte) (chval & 0xff);
8255 data[idx + 1] = (byte) (chval >> 8);
8257 case BuiltinTypeSpec.Type.Short:
8258 int sval = (int) ((short) v);
8260 data[idx] = (byte) (sval & 0xff);
8261 data[idx + 1] = (byte) (sval >> 8);
8263 case BuiltinTypeSpec.Type.UShort:
8264 int usval = (int) ((ushort) v);
8266 data[idx] = (byte) (usval & 0xff);
8267 data[idx + 1] = (byte) (usval >> 8);
8269 case BuiltinTypeSpec.Type.Int:
8272 data[idx] = (byte) (val & 0xff);
8273 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8274 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8275 data[idx + 3] = (byte) (val >> 24);
8277 case BuiltinTypeSpec.Type.UInt:
8278 uint uval = (uint) v;
8280 data[idx] = (byte) (uval & 0xff);
8281 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8282 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8283 data[idx + 3] = (byte) (uval >> 24);
8285 case BuiltinTypeSpec.Type.SByte:
8286 data[idx] = (byte) (sbyte) v;
8288 case BuiltinTypeSpec.Type.Byte:
8289 data[idx] = (byte) v;
8291 case BuiltinTypeSpec.Type.Bool:
8292 data[idx] = (byte) ((bool) v ? 1 : 0);
8294 case BuiltinTypeSpec.Type.Decimal:
8295 int[] bits = Decimal.GetBits ((decimal) v);
8298 // FIXME: For some reason, this doesn't work on the MS runtime.
8299 int[] nbits = new int[4];
8305 for (int j = 0; j < 4; j++) {
8306 data[p++] = (byte) (nbits[j] & 0xff);
8307 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8308 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8309 data[p++] = (byte) (nbits[j] >> 24);
8313 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8322 public override SLE.Expression MakeExpression (BuilderContext ctx)
8325 return base.MakeExpression (ctx);
8327 var initializers = new SLE.Expression [array_data.Count];
8328 for (var i = 0; i < initializers.Length; i++) {
8329 if (array_data [i] == null)
8330 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8332 initializers [i] = array_data [i].MakeExpression (ctx);
8335 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8340 // Emits the initializers for the array
8342 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8344 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8349 // First, the static data
8351 byte [] data = MakeByteBlob ();
8352 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8354 if (stackArray == null) {
8355 ec.Emit (OpCodes.Dup);
8357 stackArray.Emit (ec);
8360 ec.Emit (OpCodes.Ldtoken, fb);
8361 ec.Emit (OpCodes.Call, m);
8366 // Emits pieces of the array that can not be computed at compile
8367 // time (variables and string locations).
8369 // This always expect the top value on the stack to be the array
8371 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8373 int dims = bounds.Count;
8374 var current_pos = new int [dims];
8376 for (int i = 0; i < array_data.Count; i++){
8378 Expression e = array_data [i];
8379 var c = e as Constant;
8381 // Constant can be initialized via StaticInitializer
8382 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8386 if (stackArray != null) {
8387 if (e.ContainsEmitWithAwait ()) {
8388 e = e.EmitToField (ec);
8391 stackArray.EmitLoad (ec);
8393 ec.Emit (OpCodes.Dup);
8396 for (int idx = 0; idx < dims; idx++)
8397 ec.EmitInt (current_pos [idx]);
8400 // If we are dealing with a struct, get the
8401 // address of it, so we can store it.
8403 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8404 ec.Emit (OpCodes.Ldelema, etype);
8408 ec.EmitArrayStore ((ArrayContainer) type);
8414 for (int j = dims - 1; j >= 0; j--){
8416 if (current_pos [j] < bounds [j])
8418 current_pos [j] = 0;
8422 if (stackArray != null)
8423 stackArray.PrepareCleanup (ec);
8426 public override void Emit (EmitContext ec)
8428 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8431 var await_field = EmitToFieldSource (ec);
8432 if (await_field != null)
8433 await_field.Emit (ec);
8436 bool EmitOptimizedEmpty (EmitContext ec)
8438 if (arguments.Count != 1 || dimensions != 1)
8441 var c = arguments [0] as Constant;
8442 if (c == null || !c.IsZeroInteger)
8445 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8446 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8449 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8450 ec.Emit (OpCodes.Call, m);
8454 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8456 if (first_emit != null) {
8457 first_emit.Emit (ec);
8458 first_emit_temp.Store (ec);
8461 StackFieldExpr await_stack_field;
8462 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8463 await_stack_field = ec.GetTemporaryField (type);
8466 await_stack_field = null;
8469 EmitExpressionsList (ec, arguments);
8471 ec.EmitArrayNew ((ArrayContainer) type);
8473 if (initializers == null)
8474 return await_stack_field;
8476 if (await_stack_field != null)
8477 await_stack_field.EmitAssignFromStack (ec);
8481 // Emit static initializer for arrays which contain more than 2 items and
8482 // the static initializer will initialize at least 25% of array values or there
8483 // is more than 10 items to be initialized
8485 // NOTE: const_initializers_count does not contain default constant values.
8487 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8488 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8489 EmitStaticInitializers (ec, await_stack_field);
8491 if (!only_constant_initializers)
8492 EmitDynamicInitializers (ec, false, await_stack_field);
8496 EmitDynamicInitializers (ec, true, await_stack_field);
8499 if (first_emit_temp != null)
8500 first_emit_temp.Release (ec);
8502 return await_stack_field;
8505 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8507 // no multi dimensional or jagged arrays
8508 if (arguments.Count != 1 || array_element_type.IsArray) {
8509 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8513 // No array covariance, except for array -> object
8514 if (type != targetType) {
8515 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8516 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8520 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8521 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8526 // Single dimensional array of 0 size
8527 if (array_data == null) {
8528 IntConstant ic = arguments[0] as IntConstant;
8529 if (ic == null || !ic.IsDefaultValue) {
8530 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8538 enc.Encode (array_data.Count);
8539 foreach (var element in array_data) {
8540 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8544 protected override void CloneTo (CloneContext clonectx, Expression t)
8546 ArrayCreation target = (ArrayCreation) t;
8548 if (requested_base_type != null)
8549 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8551 if (arguments != null){
8552 target.arguments = new List<Expression> (arguments.Count);
8553 foreach (Expression e in arguments)
8554 target.arguments.Add (e.Clone (clonectx));
8557 if (initializers != null)
8558 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8561 public override object Accept (StructuralVisitor visitor)
8563 return visitor.Visit (this);
8568 // Represents an implicitly typed array epxression
8570 class ImplicitlyTypedArrayCreation : ArrayCreation
8572 TypeInferenceContext best_type_inference;
8574 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8575 : base (null, rank, initializers, loc)
8579 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8580 : base (null, initializers, loc)
8584 protected override Expression DoResolve (ResolveContext ec)
8589 dimensions = rank.Dimension;
8591 best_type_inference = new TypeInferenceContext ();
8593 if (!ResolveInitializers (ec))
8596 best_type_inference.FixAllTypes (ec);
8597 array_element_type = best_type_inference.InferredTypeArguments[0];
8598 best_type_inference = null;
8600 if (array_element_type == null ||
8601 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8602 arguments.Count != rank.Dimension) {
8603 ec.Report.Error (826, loc,
8604 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8609 // At this point we found common base type for all initializer elements
8610 // but we have to be sure that all static initializer elements are of
8613 UnifyInitializerElement (ec);
8615 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8616 eclass = ExprClass.Value;
8621 // Converts static initializer only
8623 void UnifyInitializerElement (ResolveContext ec)
8625 for (int i = 0; i < array_data.Count; ++i) {
8626 Expression e = array_data[i];
8628 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8632 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8634 element = element.Resolve (ec);
8635 if (element != null)
8636 best_type_inference.AddCommonTypeBound (element.Type);
8642 sealed class CompilerGeneratedThis : This
8644 public CompilerGeneratedThis (TypeSpec type, Location loc)
8650 protected override Expression DoResolve (ResolveContext rc)
8652 eclass = ExprClass.Variable;
8654 var block = rc.CurrentBlock;
8655 if (block != null) {
8656 var top = block.ParametersBlock.TopBlock;
8657 if (top.ThisVariable != null)
8658 variable_info = top.ThisVariable.VariableInfo;
8665 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8667 return DoResolve (rc);
8670 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8677 /// Represents the `this' construct
8680 public class This : VariableReference
8682 sealed class ThisVariable : ILocalVariable
8684 public static readonly ILocalVariable Instance = new ThisVariable ();
8686 public void Emit (EmitContext ec)
8691 public void EmitAssign (EmitContext ec)
8693 throw new InvalidOperationException ();
8696 public void EmitAddressOf (EmitContext ec)
8702 protected VariableInfo variable_info;
8704 public This (Location loc)
8711 public override string Name {
8712 get { return "this"; }
8715 public override bool IsLockedByStatement {
8723 public override bool IsRef {
8724 get { return type.IsStruct; }
8727 public override bool IsSideEffectFree {
8733 protected override ILocalVariable Variable {
8734 get { return ThisVariable.Instance; }
8737 public override VariableInfo VariableInfo {
8738 get { return variable_info; }
8741 public override bool IsFixed {
8742 get { return false; }
8747 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8750 // It's null for all cases when we don't need to check `this'
8751 // definitive assignment
8753 if (variable_info == null)
8756 if (fc.IsDefinitelyAssigned (variable_info))
8759 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8762 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8764 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8765 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8766 } else if (ec.CurrentAnonymousMethod != null) {
8767 ec.Report.Error (1673, loc,
8768 "Anonymous methods inside structs cannot access instance members of `this'. " +
8769 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8771 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8775 public override void FlowAnalysis (FlowAnalysisContext fc)
8777 CheckStructThisDefiniteAssignment (fc);
8780 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8785 AnonymousMethodStorey storey = ae.Storey;
8786 return storey != null ? storey.HoistedThis : null;
8789 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8791 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8794 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8797 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8803 public virtual void ResolveBase (ResolveContext ec)
8805 eclass = ExprClass.Variable;
8806 type = ec.CurrentType;
8808 if (!IsThisAvailable (ec, false)) {
8809 Error_ThisNotAvailable (ec);
8813 var block = ec.CurrentBlock;
8814 if (block != null) {
8815 var top = block.ParametersBlock.TopBlock;
8816 if (top.ThisVariable != null)
8817 variable_info = top.ThisVariable.VariableInfo;
8819 AnonymousExpression am = ec.CurrentAnonymousMethod;
8820 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8822 // Hoisted this is almost like hoisted variable but not exactly. When
8823 // there is no variable hoisted we can simply emit an instance method
8824 // without lifting this into a storey. Unfotunatelly this complicates
8825 // things in other cases because we don't know where this will be hoisted
8826 // until top-level block is fully resolved
8828 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8829 am.SetHasThisAccess ();
8834 protected override Expression DoResolve (ResolveContext ec)
8840 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8842 if (eclass == ExprClass.Unresolved)
8846 if (right_side == EmptyExpression.UnaryAddress)
8847 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8848 else if (right_side == EmptyExpression.OutAccess)
8849 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8851 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8857 public override int GetHashCode()
8859 throw new NotImplementedException ();
8862 public override bool Equals (object obj)
8864 This t = obj as This;
8871 protected override void CloneTo (CloneContext clonectx, Expression t)
8876 public override void SetHasAddressTaken ()
8881 public override object Accept (StructuralVisitor visitor)
8883 return visitor.Visit (this);
8888 /// Represents the `__arglist' construct
8890 public class ArglistAccess : Expression
8892 public ArglistAccess (Location loc)
8897 protected override void CloneTo (CloneContext clonectx, Expression target)
8902 public override bool ContainsEmitWithAwait ()
8907 public override Expression CreateExpressionTree (ResolveContext ec)
8909 throw new NotSupportedException ("ET");
8912 protected override Expression DoResolve (ResolveContext ec)
8914 eclass = ExprClass.Variable;
8915 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8917 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8918 ec.Report.Error (190, loc,
8919 "The __arglist construct is valid only within a variable argument method");
8925 public override void Emit (EmitContext ec)
8927 ec.Emit (OpCodes.Arglist);
8930 public override object Accept (StructuralVisitor visitor)
8932 return visitor.Visit (this);
8937 /// Represents the `__arglist (....)' construct
8939 public class Arglist : Expression
8941 Arguments arguments;
8943 public Arglist (Location loc)
8948 public Arglist (Arguments args, Location l)
8954 public Arguments Arguments {
8960 public MetaType[] ArgumentTypes {
8962 if (arguments == null)
8963 return MetaType.EmptyTypes;
8965 var retval = new MetaType[arguments.Count];
8966 for (int i = 0; i < retval.Length; i++)
8967 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8973 public override bool ContainsEmitWithAwait ()
8975 throw new NotImplementedException ();
8978 public override Expression CreateExpressionTree (ResolveContext ec)
8980 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8984 protected override Expression DoResolve (ResolveContext ec)
8986 eclass = ExprClass.Variable;
8987 type = InternalType.Arglist;
8988 if (arguments != null) {
8989 bool dynamic; // Can be ignored as there is always only 1 overload
8990 arguments.Resolve (ec, out dynamic);
8996 public override void Emit (EmitContext ec)
8998 if (arguments != null)
8999 arguments.Emit (ec);
9002 protected override void CloneTo (CloneContext clonectx, Expression t)
9004 Arglist target = (Arglist) t;
9006 if (arguments != null)
9007 target.arguments = arguments.Clone (clonectx);
9010 public override object Accept (StructuralVisitor visitor)
9012 return visitor.Visit (this);
9016 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9018 FullNamedExpression texpr;
9020 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9027 public FullNamedExpression TypeExpression {
9033 public override bool ContainsEmitWithAwait ()
9038 public void AddressOf (EmitContext ec, AddressOp mode)
9041 ec.Emit (OpCodes.Refanyval, type);
9044 protected override Expression DoResolve (ResolveContext rc)
9046 expr = expr.Resolve (rc);
9047 type = texpr.ResolveAsType (rc);
9048 if (expr == null || type == null)
9051 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9052 eclass = ExprClass.Variable;
9056 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9058 return DoResolve (rc);
9061 public override void Emit (EmitContext ec)
9064 ec.Emit (OpCodes.Refanyval, type);
9065 ec.EmitLoadFromPtr (type);
9068 public void Emit (EmitContext ec, bool leave_copy)
9070 throw new NotImplementedException ();
9073 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9076 ec.Emit (OpCodes.Refanyval, type);
9079 LocalTemporary temporary = null;
9081 ec.Emit (OpCodes.Dup);
9082 temporary = new LocalTemporary (source.Type);
9083 temporary.Store (ec);
9086 ec.EmitStoreFromPtr (type);
9088 if (temporary != null) {
9089 temporary.Emit (ec);
9090 temporary.Release (ec);
9094 public override object Accept (StructuralVisitor visitor)
9096 return visitor.Visit (this);
9100 public class RefTypeExpr : ShimExpression
9102 public RefTypeExpr (Expression expr, Location loc)
9108 protected override Expression DoResolve (ResolveContext rc)
9110 expr = expr.Resolve (rc);
9114 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9118 type = rc.BuiltinTypes.Type;
9119 eclass = ExprClass.Value;
9123 public override void Emit (EmitContext ec)
9126 ec.Emit (OpCodes.Refanytype);
9127 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9129 ec.Emit (OpCodes.Call, m);
9132 public override object Accept (StructuralVisitor visitor)
9134 return visitor.Visit (this);
9138 public class MakeRefExpr : ShimExpression
9140 public MakeRefExpr (Expression expr, Location loc)
9146 public override bool ContainsEmitWithAwait ()
9148 throw new NotImplementedException ();
9151 protected override Expression DoResolve (ResolveContext rc)
9153 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9154 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9155 eclass = ExprClass.Value;
9159 public override void Emit (EmitContext ec)
9161 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9162 ec.Emit (OpCodes.Mkrefany, expr.Type);
9165 public override object Accept (StructuralVisitor visitor)
9167 return visitor.Visit (this);
9172 /// Implements the typeof operator
9174 public class TypeOf : Expression {
9175 FullNamedExpression QueriedType;
9178 public TypeOf (FullNamedExpression queried_type, Location l)
9180 QueriedType = queried_type;
9185 // Use this constructor for any compiler generated typeof expression
9187 public TypeOf (TypeSpec type, Location loc)
9189 this.typearg = type;
9195 public override bool IsSideEffectFree {
9201 public TypeSpec TypeArgument {
9207 public FullNamedExpression TypeExpression {
9216 protected override void CloneTo (CloneContext clonectx, Expression t)
9218 TypeOf target = (TypeOf) t;
9219 if (QueriedType != null)
9220 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9223 public override bool ContainsEmitWithAwait ()
9228 public override Expression CreateExpressionTree (ResolveContext ec)
9230 Arguments args = new Arguments (2);
9231 args.Add (new Argument (this));
9232 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9233 return CreateExpressionFactoryCall (ec, "Constant", args);
9236 protected override Expression DoResolve (ResolveContext ec)
9238 if (eclass != ExprClass.Unresolved)
9241 if (typearg == null) {
9243 // Pointer types are allowed without explicit unsafe, they are just tokens
9245 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9246 typearg = QueriedType.ResolveAsType (ec, true);
9249 if (typearg == null)
9252 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9253 ec.Report.Error (1962, QueriedType.Location,
9254 "The typeof operator cannot be used on the dynamic type");
9258 type = ec.BuiltinTypes.Type;
9260 // Even though what is returned is a type object, it's treated as a value by the compiler.
9261 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9262 eclass = ExprClass.Value;
9266 static bool ContainsDynamicType (TypeSpec type)
9268 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9271 var element_container = type as ElementTypeSpec;
9272 if (element_container != null)
9273 return ContainsDynamicType (element_container.Element);
9275 foreach (var t in type.TypeArguments) {
9276 if (ContainsDynamicType (t)) {
9284 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9286 // Target type is not System.Type therefore must be object
9287 // and we need to use different encoding sequence
9288 if (targetType != type)
9291 if (typearg is InflatedTypeSpec) {
9294 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9295 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9296 typearg.GetSignatureForError ());
9300 gt = gt.DeclaringType;
9301 } while (gt != null);
9304 if (ContainsDynamicType (typearg)) {
9305 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9309 enc.EncodeTypeName (typearg);
9312 public override void Emit (EmitContext ec)
9314 ec.Emit (OpCodes.Ldtoken, typearg);
9315 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9317 ec.Emit (OpCodes.Call, m);
9320 public override object Accept (StructuralVisitor visitor)
9322 return visitor.Visit (this);
9326 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9328 public TypeOfMethod (MethodSpec method, Location loc)
9329 : base (method, loc)
9333 protected override Expression DoResolve (ResolveContext ec)
9335 if (member.IsConstructor) {
9336 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9338 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9344 return base.DoResolve (ec);
9347 public override void Emit (EmitContext ec)
9349 ec.Emit (OpCodes.Ldtoken, member);
9352 ec.Emit (OpCodes.Castclass, type);
9355 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9357 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9360 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9362 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9366 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9368 protected readonly T member;
9370 protected TypeOfMember (T member, Location loc)
9372 this.member = member;
9376 public override bool IsSideEffectFree {
9382 public override bool ContainsEmitWithAwait ()
9387 public override Expression CreateExpressionTree (ResolveContext ec)
9389 Arguments args = new Arguments (2);
9390 args.Add (new Argument (this));
9391 args.Add (new Argument (new TypeOf (type, loc)));
9392 return CreateExpressionFactoryCall (ec, "Constant", args);
9395 protected override Expression DoResolve (ResolveContext ec)
9397 eclass = ExprClass.Value;
9401 public override void Emit (EmitContext ec)
9403 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9404 PredefinedMember<MethodSpec> p;
9406 p = GetTypeFromHandleGeneric (ec);
9407 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9409 p = GetTypeFromHandle (ec);
9412 var mi = p.Resolve (loc);
9414 ec.Emit (OpCodes.Call, mi);
9417 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9418 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9421 sealed class TypeOfField : TypeOfMember<FieldSpec>
9423 public TypeOfField (FieldSpec field, Location loc)
9428 protected override Expression DoResolve (ResolveContext ec)
9430 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9434 return base.DoResolve (ec);
9437 public override void Emit (EmitContext ec)
9439 ec.Emit (OpCodes.Ldtoken, member);
9443 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9445 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9448 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9450 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9455 /// Implements the sizeof expression
9457 public class SizeOf : Expression {
9458 readonly Expression texpr;
9459 TypeSpec type_queried;
9461 public SizeOf (Expression queried_type, Location l)
9463 this.texpr = queried_type;
9467 public override bool IsSideEffectFree {
9473 public Expression TypeExpression {
9479 public override bool ContainsEmitWithAwait ()
9484 public override Expression CreateExpressionTree (ResolveContext ec)
9486 Error_PointerInsideExpressionTree (ec);
9490 protected override Expression DoResolve (ResolveContext ec)
9492 type_queried = texpr.ResolveAsType (ec);
9493 if (type_queried == null)
9496 if (type_queried.IsEnum)
9497 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9499 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9501 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9504 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9509 ec.Report.Error (233, loc,
9510 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9511 type_queried.GetSignatureForError ());
9514 type = ec.BuiltinTypes.Int;
9515 eclass = ExprClass.Value;
9519 public override void Emit (EmitContext ec)
9521 ec.Emit (OpCodes.Sizeof, type_queried);
9524 protected override void CloneTo (CloneContext clonectx, Expression t)
9528 public override object Accept (StructuralVisitor visitor)
9530 return visitor.Visit (this);
9535 /// Implements the qualified-alias-member (::) expression.
9537 public class QualifiedAliasMember : MemberAccess
9539 readonly string alias;
9540 public static readonly string GlobalAlias = "global";
9542 public QualifiedAliasMember (string alias, string identifier, Location l)
9543 : base (null, identifier, l)
9548 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9549 : base (null, identifier, targs, l)
9554 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9555 : base (null, identifier, arity, l)
9560 public string Alias {
9566 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9568 if (alias == GlobalAlias)
9569 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9571 int errors = mc.Module.Compiler.Report.Errors;
9572 var expr = mc.LookupNamespaceAlias (alias);
9574 if (errors == mc.Module.Compiler.Report.Errors)
9575 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9583 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9585 expr = CreateExpressionFromAlias (mc);
9589 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9592 protected override Expression DoResolve (ResolveContext rc)
9594 return ResolveAsTypeOrNamespace (rc, false);
9597 public override string GetSignatureForError ()
9600 if (targs != null) {
9601 name = Name + "<" + targs.GetSignatureForError () + ">";
9604 return alias + "::" + name;
9607 public override bool HasConditionalAccess ()
9612 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9614 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9615 rc.Module.Compiler.Report.Error (687, loc,
9616 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9617 GetSignatureForError ());
9622 return DoResolve (rc);
9625 protected override void CloneTo (CloneContext clonectx, Expression t)
9630 public override object Accept (StructuralVisitor visitor)
9632 return visitor.Visit (this);
9637 /// Implements the member access expression
9639 public class MemberAccess : ATypeNameExpression
9641 protected Expression expr;
9643 public MemberAccess (Expression expr, string id)
9644 : base (id, expr.Location)
9649 public MemberAccess (Expression expr, string identifier, Location loc)
9650 : base (identifier, loc)
9655 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9656 : base (identifier, args, loc)
9661 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9662 : base (identifier, arity, loc)
9667 public Expression LeftExpression {
9673 public override Location StartLocation {
9675 return expr == null ? loc : expr.StartLocation;
9679 protected override Expression DoResolve (ResolveContext rc)
9681 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9683 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9688 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9690 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9692 if (e is TypeExpr) {
9693 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9698 e = e.ResolveLValue (rc, rhs);
9703 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9705 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9706 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9708 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9711 public override bool HasConditionalAccess ()
9713 return LeftExpression.HasConditionalAccess ();
9716 public static bool IsValidDotExpression (TypeSpec type)
9718 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9719 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9721 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9724 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9726 var sn = expr as SimpleName;
9727 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9730 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9733 // Resolve expression which does have type set as we need expression type
9734 // with disable flow analysis as we don't know whether left side expression
9735 // is used as variable or type
9737 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9738 expr = expr.Resolve (rc);
9739 } else if (expr is TypeParameterExpr) {
9740 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9744 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9745 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9746 expr = expr.Resolve (rc, flags);
9749 expr = expr.Resolve (rc, flags);
9756 var ns = expr as NamespaceExpression;
9758 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9760 if (retval == null) {
9761 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9766 if (HasTypeArguments)
9767 return new GenericTypeExpr (retval.Type, targs, loc);
9769 targs.Resolve (rc, false);
9775 var cma = this as ConditionalMemberAccess;
9778 TypeSpec expr_type = expr.Type;
9779 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9780 me = expr as MemberExpr;
9782 me.ResolveInstanceExpression (rc, null);
9784 Arguments args = new Arguments (1);
9785 args.Add (new Argument (expr));
9788 return new DynamicConditionalMemberBinder (Name, args, loc);
9790 return new DynamicMemberBinder (Name, args, loc);
9794 if (!IsNullPropagatingValid (expr.Type)) {
9795 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9799 if (expr_type.IsNullableType) {
9800 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9801 expr_type = expr.Type;
9805 if (!IsValidDotExpression (expr_type)) {
9806 Error_OperatorCannotBeApplied (rc, expr_type);
9810 var lookup_arity = Arity;
9811 bool errorMode = false;
9812 Expression member_lookup;
9814 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9815 if (member_lookup == null) {
9817 // Try to look for extension method when member lookup failed
9819 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9820 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9821 if (methods != null) {
9822 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9823 if (HasTypeArguments) {
9824 if (!targs.Resolve (rc, false))
9827 emg.SetTypeArguments (rc, targs);
9831 emg.ConditionalAccess = true;
9833 // TODO: it should really skip the checks bellow
9834 return emg.Resolve (rc);
9840 if (member_lookup == null) {
9841 var dep = expr_type.GetMissingDependencies ();
9843 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9844 } else if (expr is TypeExpr) {
9845 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9847 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9853 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9854 // Leave it to overload resolution to report correct error
9855 } else if (!(member_lookup is TypeExpr)) {
9856 // TODO: rc.SymbolRelatedToPreviousError
9857 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9862 if (member_lookup != null)
9866 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9870 TypeExpr texpr = member_lookup as TypeExpr;
9871 if (texpr != null) {
9872 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9873 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9874 Name, texpr.GetSignatureForError ());
9877 if (!texpr.Type.IsAccessible (rc)) {
9878 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9879 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9883 if (HasTypeArguments) {
9884 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9887 return member_lookup;
9890 me = member_lookup as MemberExpr;
9892 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9897 me.ConditionalAccess = true;
9900 me = me.ResolveMemberAccess (rc, expr, sn);
9903 if (!targs.Resolve (rc, false))
9906 me.SetTypeArguments (rc, targs);
9912 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9914 FullNamedExpression fexpr = expr as FullNamedExpression;
9915 if (fexpr == null) {
9916 expr.ResolveAsType (rc);
9920 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9922 if (expr_resolved == null)
9925 var ns = expr_resolved as NamespaceExpression;
9927 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9929 if (retval == null) {
9930 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9931 } else if (Arity > 0) {
9932 if (HasTypeArguments) {
9933 retval = new GenericTypeExpr (retval.Type, targs, loc);
9934 if (retval.ResolveAsType (rc) == null)
9937 targs.Resolve (rc, allowUnboundTypeArguments);
9939 retval = new GenericOpenTypeExpr (retval.Type, loc);
9946 var tnew_expr = expr_resolved.ResolveAsType (rc);
9947 if (tnew_expr == null)
9950 TypeSpec expr_type = tnew_expr;
9951 if (TypeManager.IsGenericParameter (expr_type)) {
9952 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9953 tnew_expr.GetSignatureForError ());
9957 var qam = this as QualifiedAliasMember;
9959 rc.Module.Compiler.Report.Error (431, loc,
9960 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9965 TypeSpec nested = null;
9966 while (expr_type != null) {
9967 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9968 if (nested == null) {
9969 if (expr_type == tnew_expr) {
9970 Error_IdentifierNotFound (rc, expr_type);
9974 expr_type = tnew_expr;
9975 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
9976 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9980 if (nested.IsAccessible (rc))
9984 // Keep looking after inaccessible candidate but only if
9985 // we are not in same context as the definition itself
9987 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9990 expr_type = expr_type.BaseType;
9995 if (HasTypeArguments) {
9996 texpr = new GenericTypeExpr (nested, targs, loc);
9998 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10000 texpr = new GenericOpenTypeExpr (nested, loc);
10002 } else if (expr_resolved is GenericOpenTypeExpr) {
10003 texpr = new GenericOpenTypeExpr (nested, loc);
10005 texpr = new TypeExpression (nested, loc);
10008 if (texpr.ResolveAsType (rc) == null)
10014 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10016 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10018 if (nested != null) {
10019 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10023 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10024 if (any_other_member != null) {
10025 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10029 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10030 Name, expr_type.GetSignatureForError ());
10033 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10035 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10038 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10040 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10041 ec.Report.SymbolRelatedToPreviousError (type);
10043 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10045 // a using directive or an assembly reference
10046 if (cand != null) {
10047 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10049 missing = "an assembly reference";
10052 ec.Report.Error (1061, loc,
10053 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10054 type.GetSignatureForError (), name, missing);
10058 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10061 public override string GetSignatureForError ()
10063 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10066 protected override void CloneTo (CloneContext clonectx, Expression t)
10068 MemberAccess target = (MemberAccess) t;
10070 target.expr = expr.Clone (clonectx);
10073 public override object Accept (StructuralVisitor visitor)
10075 return visitor.Visit (this);
10079 public class ConditionalMemberAccess : MemberAccess
10081 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10082 : base (expr, identifier, args, loc)
10086 public override bool HasConditionalAccess ()
10093 /// Implements checked expressions
10095 public class CheckedExpr : Expression {
10097 public Expression Expr;
10099 public CheckedExpr (Expression e, Location l)
10105 public override bool ContainsEmitWithAwait ()
10107 return Expr.ContainsEmitWithAwait ();
10110 public override Expression CreateExpressionTree (ResolveContext ec)
10112 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10113 return Expr.CreateExpressionTree (ec);
10116 protected override Expression DoResolve (ResolveContext ec)
10118 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10119 Expr = Expr.Resolve (ec);
10124 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10127 eclass = Expr.eclass;
10132 public override void Emit (EmitContext ec)
10134 using (ec.With (EmitContext.Options.CheckedScope, true))
10138 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10140 using (ec.With (EmitContext.Options.CheckedScope, true))
10141 Expr.EmitBranchable (ec, target, on_true);
10144 public override void FlowAnalysis (FlowAnalysisContext fc)
10146 Expr.FlowAnalysis (fc);
10149 public override SLE.Expression MakeExpression (BuilderContext ctx)
10151 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10152 return Expr.MakeExpression (ctx);
10156 protected override void CloneTo (CloneContext clonectx, Expression t)
10158 CheckedExpr target = (CheckedExpr) t;
10160 target.Expr = Expr.Clone (clonectx);
10163 public override object Accept (StructuralVisitor visitor)
10165 return visitor.Visit (this);
10170 /// Implements the unchecked expression
10172 public class UnCheckedExpr : Expression {
10174 public Expression Expr;
10176 public UnCheckedExpr (Expression e, Location l)
10182 public override bool ContainsEmitWithAwait ()
10184 return Expr.ContainsEmitWithAwait ();
10187 public override Expression CreateExpressionTree (ResolveContext ec)
10189 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10190 return Expr.CreateExpressionTree (ec);
10193 protected override Expression DoResolve (ResolveContext ec)
10195 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10196 Expr = Expr.Resolve (ec);
10201 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10204 eclass = Expr.eclass;
10209 public override void Emit (EmitContext ec)
10211 using (ec.With (EmitContext.Options.CheckedScope, false))
10215 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10217 using (ec.With (EmitContext.Options.CheckedScope, false))
10218 Expr.EmitBranchable (ec, target, on_true);
10221 public override void FlowAnalysis (FlowAnalysisContext fc)
10223 Expr.FlowAnalysis (fc);
10226 protected override void CloneTo (CloneContext clonectx, Expression t)
10228 UnCheckedExpr target = (UnCheckedExpr) t;
10230 target.Expr = Expr.Clone (clonectx);
10233 public override object Accept (StructuralVisitor visitor)
10235 return visitor.Visit (this);
10240 /// An Element Access expression.
10242 /// During semantic analysis these are transformed into
10243 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10245 public class ElementAccess : Expression
10247 public Arguments Arguments;
10248 public Expression Expr;
10249 bool conditional_access_receiver;
10251 public ElementAccess (Expression e, Arguments args, Location loc)
10255 this.Arguments = args;
10258 public bool ConditionalAccess { get; set; }
10260 public override Location StartLocation {
10262 return Expr.StartLocation;
10266 public override bool ContainsEmitWithAwait ()
10268 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10272 // We perform some simple tests, and then to "split" the emit and store
10273 // code we create an instance of a different class, and return that.
10275 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10277 if (conditionalAccessReceiver)
10278 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10280 Expr = Expr.Resolve (ec);
10282 if (conditionalAccessReceiver)
10283 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10290 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10291 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10295 if (type.IsArray) {
10296 var aa = new ArrayAccess (this, loc) {
10297 ConditionalAccess = ConditionalAccess,
10300 if (conditionalAccessReceiver)
10301 aa.SetConditionalAccessReceiver ();
10306 if (type.IsPointer)
10307 return Expr.MakePointerAccess (ec, type, Arguments);
10309 FieldExpr fe = Expr as FieldExpr;
10311 var ff = fe.Spec as FixedFieldSpec;
10313 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10317 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10318 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10319 var indexer = new IndexerExpr (indexers, type, this) {
10320 ConditionalAccess = ConditionalAccess
10323 if (conditionalAccessReceiver)
10324 indexer.SetConditionalAccessReceiver ();
10329 Error_CannotApplyIndexing (ec, type, loc);
10334 public override Expression CreateExpressionTree (ResolveContext ec)
10336 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10337 Expr.CreateExpressionTree (ec));
10339 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10342 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10344 if (type != InternalType.ErrorType) {
10345 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10346 type.GetSignatureForError ());
10350 public override bool HasConditionalAccess ()
10352 return ConditionalAccess || Expr.HasConditionalAccess ();
10355 void ResolveConditionalAccessReceiver (ResolveContext rc)
10357 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10358 conditional_access_receiver = true;
10362 protected override Expression DoResolve (ResolveContext rc)
10364 ResolveConditionalAccessReceiver (rc);
10366 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10370 return expr.Resolve (rc);
10373 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10375 var res = CreateAccessExpression (ec, false);
10379 return res.ResolveLValue (ec, rhs);
10382 public override void Emit (EmitContext ec)
10384 throw new Exception ("Should never be reached");
10387 public override void FlowAnalysis (FlowAnalysisContext fc)
10389 Expr.FlowAnalysis (fc);
10391 Arguments.FlowAnalysis (fc);
10394 public override string GetSignatureForError ()
10396 return Expr.GetSignatureForError ();
10399 protected override void CloneTo (CloneContext clonectx, Expression t)
10401 ElementAccess target = (ElementAccess) t;
10403 target.Expr = Expr.Clone (clonectx);
10404 if (Arguments != null)
10405 target.Arguments = Arguments.Clone (clonectx);
10408 public override object Accept (StructuralVisitor visitor)
10410 return visitor.Visit (this);
10415 /// Implements array access
10417 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10419 // Points to our "data" repository
10423 LocalTemporary temp;
10425 bool? has_await_args;
10426 bool conditional_access_receiver;
10428 public ArrayAccess (ElementAccess ea_data, Location l)
10434 public bool ConditionalAccess { get; set; }
10436 public void AddressOf (EmitContext ec, AddressOp mode)
10438 var ac = (ArrayContainer) ea.Expr.Type;
10440 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10441 LoadInstanceAndArguments (ec, false, true);
10444 LoadInstanceAndArguments (ec, false, false);
10446 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10447 ec.Emit (OpCodes.Readonly);
10449 ec.EmitArrayAddress (ac);
10452 public override Expression CreateExpressionTree (ResolveContext ec)
10454 if (ConditionalAccess)
10455 Error_NullShortCircuitInsideExpressionTree (ec);
10457 return ea.CreateExpressionTree (ec);
10460 public override bool ContainsEmitWithAwait ()
10462 return ea.ContainsEmitWithAwait ();
10465 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10467 if (HasConditionalAccess ())
10468 Error_NullPropagatingLValue (ec);
10470 return DoResolve (ec);
10473 protected override Expression DoResolve (ResolveContext ec)
10475 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10477 ea.Arguments.Resolve (ec, out dynamic);
10479 var ac = ea.Expr.Type as ArrayContainer;
10480 int rank = ea.Arguments.Count;
10481 if (ac.Rank != rank) {
10482 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10483 rank.ToString (), ac.Rank.ToString ());
10488 if (type.IsPointer && !ec.IsUnsafe) {
10489 UnsafeError (ec, ea.Location);
10492 if (conditional_access_receiver)
10493 type = LiftMemberType (ec, type);
10495 foreach (Argument a in ea.Arguments) {
10496 var na = a as NamedArgument;
10498 ElementAccess.Error_NamedArgument (na, ec.Report);
10500 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10503 eclass = ExprClass.Variable;
10508 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10510 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10513 public override void FlowAnalysis (FlowAnalysisContext fc)
10515 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10517 ea.FlowAnalysis (fc);
10519 if (conditional_access_receiver)
10520 fc.DefiniteAssignment = da;
10523 public override bool HasConditionalAccess ()
10525 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10529 // Load the array arguments into the stack.
10531 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10533 if (prepareAwait) {
10534 ea.Expr = ea.Expr.EmitToField (ec);
10536 var ie = new InstanceEmitter (ea.Expr, false);
10537 ie.Emit (ec, ConditionalAccess);
10539 if (duplicateArguments) {
10540 ec.Emit (OpCodes.Dup);
10542 var copy = new LocalTemporary (ea.Expr.Type);
10548 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10549 if (dup_args != null)
10550 ea.Arguments = dup_args;
10553 public void Emit (EmitContext ec, bool leave_copy)
10556 ec.EmitLoadFromPtr (type);
10558 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10559 LoadInstanceAndArguments (ec, false, true);
10562 if (conditional_access_receiver)
10563 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10565 var ac = (ArrayContainer) ea.Expr.Type;
10566 LoadInstanceAndArguments (ec, false, false);
10567 ec.EmitArrayLoad (ac);
10569 if (conditional_access_receiver)
10570 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10574 ec.Emit (OpCodes.Dup);
10575 temp = new LocalTemporary (this.type);
10580 public override void Emit (EmitContext ec)
10585 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10587 var ac = (ArrayContainer) ea.Expr.Type;
10588 TypeSpec t = source.Type;
10590 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10593 // When we are dealing with a struct, get the address of it to avoid value copy
10594 // Same cannot be done for reference type because array covariance and the
10595 // check in ldelema requires to specify the type of array element stored at the index
10597 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10598 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10600 if (has_await_args.Value) {
10601 if (source.ContainsEmitWithAwait ()) {
10602 source = source.EmitToField (ec);
10603 isCompound = false;
10607 LoadInstanceAndArguments (ec, isCompound, false);
10612 ec.EmitArrayAddress (ac);
10615 ec.Emit (OpCodes.Dup);
10619 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10621 if (has_await_args.Value) {
10622 if (source.ContainsEmitWithAwait ())
10623 source = source.EmitToField (ec);
10625 LoadInstanceAndArguments (ec, false, false);
10632 var lt = ea.Expr as LocalTemporary;
10638 ec.Emit (OpCodes.Dup);
10639 temp = new LocalTemporary (this.type);
10644 ec.EmitStoreFromPtr (t);
10646 ec.EmitArrayStore (ac);
10649 if (temp != null) {
10655 public override Expression EmitToField (EmitContext ec)
10658 // Have to be specialized for arrays to get access to
10659 // underlying element. Instead of another result copy we
10660 // need direct access to element
10664 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10666 ea.Expr = ea.Expr.EmitToField (ec);
10667 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10671 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10673 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10676 public override SLE.Expression MakeExpression (BuilderContext ctx)
10678 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10681 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10683 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10684 return Arguments.MakeExpression (ea.Arguments, ctx);
10688 public void SetConditionalAccessReceiver ()
10690 conditional_access_receiver = true;
10695 // Indexer access expression
10697 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10699 IList<MemberSpec> indexers;
10700 Arguments arguments;
10701 TypeSpec queried_type;
10703 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10704 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10708 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10711 this.indexers = indexers;
10712 this.queried_type = queriedType;
10713 this.InstanceExpression = instance;
10714 this.arguments = args;
10719 protected override Arguments Arguments {
10728 protected override TypeSpec DeclaringType {
10730 return best_candidate.DeclaringType;
10734 public override bool IsInstance {
10740 public override bool IsStatic {
10746 public override string KindName {
10747 get { return "indexer"; }
10750 public override string Name {
10758 public override bool ContainsEmitWithAwait ()
10760 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10763 public override Expression CreateExpressionTree (ResolveContext ec)
10765 if (ConditionalAccess) {
10766 Error_NullShortCircuitInsideExpressionTree (ec);
10769 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10770 InstanceExpression.CreateExpressionTree (ec),
10771 new TypeOfMethod (Getter, loc));
10773 return CreateExpressionFactoryCall (ec, "Call", args);
10776 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10778 LocalTemporary await_source_arg = null;
10781 emitting_compound_assignment = true;
10782 if (source is DynamicExpressionStatement) {
10787 emitting_compound_assignment = false;
10789 if (has_await_arguments) {
10790 await_source_arg = new LocalTemporary (Type);
10791 await_source_arg.Store (ec);
10793 arguments.Add (new Argument (await_source_arg));
10796 temp = await_source_arg;
10799 has_await_arguments = false;
10804 ec.Emit (OpCodes.Dup);
10805 temp = new LocalTemporary (Type);
10811 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10812 source = source.EmitToField (ec);
10814 temp = new LocalTemporary (Type);
10821 arguments.Add (new Argument (source));
10824 var call = new CallEmitter ();
10825 call.InstanceExpression = InstanceExpression;
10826 if (arguments == null)
10827 call.InstanceExpressionOnStack = true;
10829 call.Emit (ec, Setter, arguments, loc);
10831 if (temp != null) {
10834 } else if (leave_copy) {
10838 if (await_source_arg != null) {
10839 await_source_arg.Release (ec);
10843 public override void FlowAnalysis (FlowAnalysisContext fc)
10845 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10847 base.FlowAnalysis (fc);
10848 arguments.FlowAnalysis (fc);
10850 if (conditional_access_receiver)
10851 fc.DefiniteAssignment = da;
10854 public override string GetSignatureForError ()
10856 return best_candidate.GetSignatureForError ();
10859 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10862 throw new NotSupportedException ();
10864 var value = new[] { source.MakeExpression (ctx) };
10865 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10866 return SLE.Expression.Block (
10867 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10872 public override SLE.Expression MakeExpression (BuilderContext ctx)
10875 return base.MakeExpression (ctx);
10877 var args = Arguments.MakeExpression (arguments, ctx);
10878 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10882 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10884 if (best_candidate != null)
10887 eclass = ExprClass.IndexerAccess;
10890 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10891 arguments.Resolve (rc, out dynamic);
10894 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10897 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10898 res.BaseMembersProvider = this;
10899 res.InstanceQualifier = this;
10901 // TODO: Do I need 2 argument sets?
10902 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10903 if (best_candidate != null)
10904 type = res.BestCandidateReturnType;
10905 else if (!res.BestCandidateIsDynamic)
10910 // It has dynamic arguments
10913 Arguments args = new Arguments (arguments.Count + 1);
10915 rc.Report.Error (1972, loc,
10916 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10918 args.Add (new Argument (InstanceExpression));
10920 args.AddRange (arguments);
10922 best_candidate = null;
10923 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10927 // Try to avoid resolving left expression again
10929 if (right_side != null)
10930 ResolveInstanceExpression (rc, right_side);
10935 protected override void CloneTo (CloneContext clonectx, Expression t)
10937 IndexerExpr target = (IndexerExpr) t;
10939 if (arguments != null)
10940 target.arguments = arguments.Clone (clonectx);
10943 public void SetConditionalAccessReceiver ()
10945 conditional_access_receiver = true;
10948 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10950 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10953 #region IBaseMembersProvider Members
10955 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
10957 var baseType = type.BaseType;
10958 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10960 if (members == null && !type.IsInterface) {
10961 var tps = queried_type as TypeParameterSpec;
10963 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
10969 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10971 if (queried_type == member.DeclaringType)
10974 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10975 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10978 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10987 // A base access expression
10989 public class BaseThis : This
10991 public BaseThis (Location loc)
10996 public BaseThis (TypeSpec type, Location loc)
11000 eclass = ExprClass.Variable;
11005 public override string Name {
11013 public override Expression CreateExpressionTree (ResolveContext ec)
11015 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11016 return base.CreateExpressionTree (ec);
11019 public override void Emit (EmitContext ec)
11023 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11024 var context_type = ec.CurrentType;
11025 ec.Emit (OpCodes.Ldobj, context_type);
11026 ec.Emit (OpCodes.Box, context_type);
11030 protected override void Error_ThisNotAvailable (ResolveContext ec)
11033 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11035 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11039 public override void ResolveBase (ResolveContext ec)
11041 base.ResolveBase (ec);
11042 type = ec.CurrentType.BaseType;
11045 public override object Accept (StructuralVisitor visitor)
11047 return visitor.Visit (this);
11052 /// This class exists solely to pass the Type around and to be a dummy
11053 /// that can be passed to the conversion functions (this is used by
11054 /// foreach implementation to typecast the object return value from
11055 /// get_Current into the proper type. All code has been generated and
11056 /// we only care about the side effect conversions to be performed
11058 /// This is also now used as a placeholder where a no-action expression
11059 /// is needed (the `New' class).
11061 public class EmptyExpression : Expression
11063 sealed class OutAccessExpression : EmptyExpression
11065 public OutAccessExpression (TypeSpec t)
11070 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11072 rc.Report.Error (206, right_side.Location,
11073 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11079 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11080 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11081 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11082 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11083 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11084 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11085 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11086 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11088 public EmptyExpression (TypeSpec t)
11091 eclass = ExprClass.Value;
11092 loc = Location.Null;
11095 protected override void CloneTo (CloneContext clonectx, Expression target)
11099 public override bool ContainsEmitWithAwait ()
11104 public override Expression CreateExpressionTree (ResolveContext ec)
11106 throw new NotSupportedException ("ET");
11109 protected override Expression DoResolve (ResolveContext ec)
11114 public override void Emit (EmitContext ec)
11116 // nothing, as we only exist to not do anything.
11119 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11123 public override void EmitSideEffect (EmitContext ec)
11127 public override object Accept (StructuralVisitor visitor)
11129 return visitor.Visit (this);
11133 sealed class EmptyAwaitExpression : EmptyExpression
11135 public EmptyAwaitExpression (TypeSpec type)
11140 public override bool ContainsEmitWithAwait ()
11147 // Empty statement expression
11149 public sealed class EmptyExpressionStatement : ExpressionStatement
11151 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11153 private EmptyExpressionStatement ()
11155 loc = Location.Null;
11158 public override bool ContainsEmitWithAwait ()
11163 public override Expression CreateExpressionTree (ResolveContext ec)
11168 public override void EmitStatement (EmitContext ec)
11173 protected override Expression DoResolve (ResolveContext ec)
11175 eclass = ExprClass.Value;
11176 type = ec.BuiltinTypes.Object;
11180 public override void Emit (EmitContext ec)
11185 public override object Accept (StructuralVisitor visitor)
11187 return visitor.Visit (this);
11191 public class ErrorExpression : EmptyExpression
11193 public static readonly ErrorExpression Instance = new ErrorExpression ();
11195 private ErrorExpression ()
11196 : base (InternalType.ErrorType)
11200 public override Expression CreateExpressionTree (ResolveContext ec)
11205 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11210 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11214 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11218 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11222 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11226 public override object Accept (StructuralVisitor visitor)
11228 return visitor.Visit (this);
11232 public class UserCast : Expression {
11236 public UserCast (MethodSpec method, Expression source, Location l)
11238 if (source == null)
11239 throw new ArgumentNullException ("source");
11241 this.method = method;
11242 this.source = source;
11243 type = method.ReturnType;
11247 public Expression Source {
11256 public override bool ContainsEmitWithAwait ()
11258 return source.ContainsEmitWithAwait ();
11261 public override Expression CreateExpressionTree (ResolveContext ec)
11263 Arguments args = new Arguments (3);
11264 args.Add (new Argument (source.CreateExpressionTree (ec)));
11265 args.Add (new Argument (new TypeOf (type, loc)));
11266 args.Add (new Argument (new TypeOfMethod (method, loc)));
11267 return CreateExpressionFactoryCall (ec, "Convert", args);
11270 protected override Expression DoResolve (ResolveContext ec)
11272 method.CheckObsoleteness (ec, source.Location);
11274 eclass = ExprClass.Value;
11278 public override void Emit (EmitContext ec)
11281 ec.MarkCallEntry (loc);
11282 ec.Emit (OpCodes.Call, method);
11285 public override void FlowAnalysis (FlowAnalysisContext fc)
11287 source.FlowAnalysis (fc);
11290 public override string GetSignatureForError ()
11292 return TypeManager.CSharpSignature (method);
11295 public override SLE.Expression MakeExpression (BuilderContext ctx)
11298 return base.MakeExpression (ctx);
11300 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11306 // Holds additional type specifiers like ?, *, []
11308 public class ComposedTypeSpecifier
11310 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11312 public readonly int Dimension;
11313 public readonly Location Location;
11315 public ComposedTypeSpecifier (int specifier, Location loc)
11317 this.Dimension = specifier;
11318 this.Location = loc;
11322 public bool IsNullable {
11324 return Dimension == -1;
11328 public bool IsPointer {
11330 return Dimension == -2;
11334 public ComposedTypeSpecifier Next { get; set; }
11338 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11340 return new ComposedTypeSpecifier (dimension, loc);
11343 public static ComposedTypeSpecifier CreateNullable (Location loc)
11345 return new ComposedTypeSpecifier (-1, loc);
11348 public static ComposedTypeSpecifier CreatePointer (Location loc)
11350 return new ComposedTypeSpecifier (-2, loc);
11353 public string GetSignatureForError ()
11358 ArrayContainer.GetPostfixSignature (Dimension);
11360 return Next != null ? s + Next.GetSignatureForError () : s;
11365 // This class is used to "construct" the type during a typecast
11366 // operation. Since the Type.GetType class in .NET can parse
11367 // the type specification, we just use this to construct the type
11368 // one bit at a time.
11370 public class ComposedCast : TypeExpr {
11371 FullNamedExpression left;
11372 ComposedTypeSpecifier spec;
11374 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11377 throw new ArgumentNullException ("spec");
11381 this.loc = left.Location;
11384 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11386 type = left.ResolveAsType (ec);
11390 eclass = ExprClass.Type;
11392 var single_spec = spec;
11394 if (single_spec.IsNullable) {
11395 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11399 single_spec = single_spec.Next;
11400 } else if (single_spec.IsPointer) {
11402 // Declared fields cannot have unmanaged check done before all types are defined
11404 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11407 if (!ec.IsUnsafe) {
11408 UnsafeError (ec.Module.Compiler.Report, loc);
11412 type = PointerContainer.MakeType (ec.Module, type);
11413 single_spec = single_spec.Next;
11414 } while (single_spec != null && single_spec.IsPointer);
11417 if (single_spec != null && single_spec.Dimension > 0) {
11418 if (type.IsSpecialRuntimeType) {
11419 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11420 } else if (type.IsStatic) {
11421 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11422 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11423 type.GetSignatureForError ());
11425 MakeArray (ec.Module, single_spec);
11432 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11434 if (spec.Next != null)
11435 MakeArray (module, spec.Next);
11437 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11440 public override string GetSignatureForError ()
11442 return left.GetSignatureForError () + spec.GetSignatureForError ();
11445 public override object Accept (StructuralVisitor visitor)
11447 return visitor.Visit (this);
11451 class FixedBufferPtr : Expression
11453 readonly Expression array;
11455 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11457 this.type = array_type;
11458 this.array = array;
11462 public override bool ContainsEmitWithAwait ()
11464 throw new NotImplementedException ();
11467 public override Expression CreateExpressionTree (ResolveContext ec)
11469 Error_PointerInsideExpressionTree (ec);
11473 public override void Emit(EmitContext ec)
11478 protected override Expression DoResolve (ResolveContext ec)
11480 type = PointerContainer.MakeType (ec.Module, type);
11481 eclass = ExprClass.Value;
11488 // This class is used to represent the address of an array, used
11489 // only by the Fixed statement, this generates "&a [0]" construct
11490 // for fixed (char *pa = a)
11492 class ArrayPtr : FixedBufferPtr
11494 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11495 base (array, array_type, l)
11499 public override void Emit (EmitContext ec)
11504 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11509 // Encapsulates a conversion rules required for array indexes
11511 public class ArrayIndexCast : TypeCast
11513 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11514 : base (expr, returnType)
11516 if (expr.Type == returnType) // int -> int
11517 throw new ArgumentException ("unnecessary array index conversion");
11520 public override Expression CreateExpressionTree (ResolveContext ec)
11522 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11523 return base.CreateExpressionTree (ec);
11527 public override void Emit (EmitContext ec)
11531 switch (child.Type.BuiltinType) {
11532 case BuiltinTypeSpec.Type.UInt:
11533 ec.Emit (OpCodes.Conv_U);
11535 case BuiltinTypeSpec.Type.Long:
11536 ec.Emit (OpCodes.Conv_Ovf_I);
11538 case BuiltinTypeSpec.Type.ULong:
11539 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11542 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11548 // Implements the `stackalloc' keyword
11550 public class StackAlloc : Expression {
11555 public StackAlloc (Expression type, Expression count, Location l)
11558 this.count = count;
11562 public Expression TypeExpression {
11568 public Expression CountExpression {
11574 public override bool ContainsEmitWithAwait ()
11579 public override Expression CreateExpressionTree (ResolveContext ec)
11581 throw new NotSupportedException ("ET");
11584 protected override Expression DoResolve (ResolveContext ec)
11586 count = count.Resolve (ec);
11590 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11591 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11596 Constant c = count as Constant;
11597 if (c != null && c.IsNegative) {
11598 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11601 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11602 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11605 otype = texpr.ResolveAsType (ec);
11609 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11612 type = PointerContainer.MakeType (ec.Module, otype);
11613 eclass = ExprClass.Value;
11618 public override void Emit (EmitContext ec)
11620 int size = BuiltinTypeSpec.GetSize (otype);
11625 ec.Emit (OpCodes.Sizeof, otype);
11629 ec.Emit (OpCodes.Mul_Ovf_Un);
11630 ec.Emit (OpCodes.Localloc);
11633 protected override void CloneTo (CloneContext clonectx, Expression t)
11635 StackAlloc target = (StackAlloc) t;
11636 target.count = count.Clone (clonectx);
11637 target.texpr = texpr.Clone (clonectx);
11640 public override object Accept (StructuralVisitor visitor)
11642 return visitor.Visit (this);
11647 // An object initializer expression
11649 public class ElementInitializer : Assign
11651 public readonly string Name;
11653 public ElementInitializer (string name, Expression initializer, Location loc)
11654 : base (null, initializer, loc)
11659 public bool IsDictionaryInitializer {
11661 return Name == null;
11665 protected override void CloneTo (CloneContext clonectx, Expression t)
11667 ElementInitializer target = (ElementInitializer) t;
11668 target.source = source.Clone (clonectx);
11671 public override Expression CreateExpressionTree (ResolveContext ec)
11673 Arguments args = new Arguments (2);
11674 FieldExpr fe = target as FieldExpr;
11676 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11678 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11681 Expression arg_expr;
11682 var cinit = source as CollectionOrObjectInitializers;
11683 if (cinit == null) {
11685 arg_expr = source.CreateExpressionTree (ec);
11687 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11688 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11691 args.Add (new Argument (arg_expr));
11692 return CreateExpressionFactoryCall (ec, mname, args);
11695 protected override Expression DoResolve (ResolveContext ec)
11697 if (source == null)
11698 return EmptyExpressionStatement.Instance;
11700 if (!ResolveElement (ec))
11703 if (source is CollectionOrObjectInitializers) {
11704 target = target.Resolve (ec);
11705 if (target == null)
11708 Expression previous = ec.CurrentInitializerVariable;
11709 ec.CurrentInitializerVariable = target;
11710 source = source.Resolve (ec);
11711 ec.CurrentInitializerVariable = previous;
11712 if (source == null)
11715 eclass = source.eclass;
11716 type = source.Type;
11721 return base.DoResolve (ec);
11724 public override void EmitStatement (EmitContext ec)
11726 if (source is CollectionOrObjectInitializers)
11729 base.EmitStatement (ec);
11732 protected virtual bool ResolveElement (ResolveContext rc)
11734 var t = rc.CurrentInitializerVariable.Type;
11735 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11736 Arguments args = new Arguments (1);
11737 args.Add (new Argument (rc.CurrentInitializerVariable));
11738 target = new DynamicMemberBinder (Name, args, loc);
11740 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11741 if (member == null) {
11742 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11744 if (member != null) {
11745 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11746 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11751 if (member == null) {
11752 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11756 var me = member as MemberExpr;
11757 if (me is EventExpr) {
11758 me = me.ResolveMemberAccess (rc, null, null);
11759 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11760 rc.Report.Error (1913, loc,
11761 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11762 member.GetSignatureForError ());
11768 rc.Report.Error (1914, loc,
11769 "Static field or property `{0}' cannot be assigned in an object initializer",
11770 me.GetSignatureForError ());
11774 me.InstanceExpression = rc.CurrentInitializerVariable;
11782 // A collection initializer expression
11784 class CollectionElementInitializer : Invocation
11786 public class ElementInitializerArgument : Argument
11788 public ElementInitializerArgument (Expression e)
11794 sealed class AddMemberAccess : MemberAccess
11796 public AddMemberAccess (Expression expr, Location loc)
11797 : base (expr, "Add", loc)
11801 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11803 if (TypeManager.HasElementType (type))
11806 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11810 public CollectionElementInitializer (Expression argument)
11811 : base (null, new Arguments (1))
11813 base.arguments.Add (new ElementInitializerArgument (argument));
11814 this.loc = argument.Location;
11817 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11818 : base (null, new Arguments (arguments.Count))
11820 foreach (Expression e in arguments)
11821 base.arguments.Add (new ElementInitializerArgument (e));
11826 public CollectionElementInitializer (Location loc)
11827 : base (null, null)
11832 public override Expression CreateExpressionTree (ResolveContext ec)
11834 Arguments args = new Arguments (2);
11835 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11837 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11838 foreach (Argument a in arguments) {
11839 if (a.ArgType == Argument.AType.ExtensionType) {
11840 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11843 expr_initializers.Add (a.CreateExpressionTree (ec));
11846 args.Add (new Argument (new ArrayCreation (
11847 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11848 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11851 protected override void CloneTo (CloneContext clonectx, Expression t)
11853 CollectionElementInitializer target = (CollectionElementInitializer) t;
11854 if (arguments != null)
11855 target.arguments = arguments.Clone (clonectx);
11858 protected override Expression DoResolve (ResolveContext ec)
11860 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11862 return base.DoResolve (ec);
11866 class DictionaryElementInitializer : ElementInitializer
11868 readonly Arguments args;
11870 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11871 : base (null, initializer, loc)
11873 this.args = arguments;
11876 public override Expression CreateExpressionTree (ResolveContext ec)
11878 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11882 protected override bool ResolveElement (ResolveContext rc)
11884 var init = rc.CurrentInitializerVariable;
11885 var type = init.Type;
11887 if (type.IsArray) {
11888 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11892 if (type.IsPointer) {
11893 target = init.MakePointerAccess (rc, type, args);
11897 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11898 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11899 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11903 target = new IndexerExpr (indexers, type, init, args, loc);
11909 // A block of object or collection initializers
11911 public class CollectionOrObjectInitializers : ExpressionStatement
11913 IList<Expression> initializers;
11914 bool is_collection_initialization;
11916 public CollectionOrObjectInitializers (Location loc)
11917 : this (new Expression[0], loc)
11921 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11923 this.initializers = initializers;
11927 public IList<Expression> Initializers {
11929 return initializers;
11933 public bool IsEmpty {
11935 return initializers.Count == 0;
11939 public bool IsCollectionInitializer {
11941 return is_collection_initialization;
11945 protected override void CloneTo (CloneContext clonectx, Expression target)
11947 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11949 t.initializers = new List<Expression> (initializers.Count);
11950 foreach (var e in initializers)
11951 t.initializers.Add (e.Clone (clonectx));
11954 public override bool ContainsEmitWithAwait ()
11956 foreach (var e in initializers) {
11957 if (e.ContainsEmitWithAwait ())
11964 public override Expression CreateExpressionTree (ResolveContext ec)
11966 return CreateExpressionTree (ec, false);
11969 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11971 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11972 foreach (Expression e in initializers) {
11973 Expression expr = e.CreateExpressionTree (ec);
11975 expr_initializers.Add (expr);
11979 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11981 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11984 protected override Expression DoResolve (ResolveContext ec)
11986 List<string> element_names = null;
11987 for (int i = 0; i < initializers.Count; ++i) {
11988 Expression initializer = initializers [i];
11989 ElementInitializer element_initializer = initializer as ElementInitializer;
11992 if (element_initializer != null) {
11993 element_names = new List<string> (initializers.Count);
11994 if (!element_initializer.IsDictionaryInitializer)
11995 element_names.Add (element_initializer.Name);
11996 } else if (initializer is CompletingExpression) {
11997 initializer.Resolve (ec);
11998 throw new InternalErrorException ("This line should never be reached");
12000 var t = ec.CurrentInitializerVariable.Type;
12001 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12002 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12003 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12004 "object initializer because type `{1}' does not implement `{2}' interface",
12005 ec.CurrentInitializerVariable.GetSignatureForError (),
12006 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12007 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12010 is_collection_initialization = true;
12013 if (is_collection_initialization != (element_initializer == null)) {
12014 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12015 is_collection_initialization ? "collection initializer" : "object initializer");
12019 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12020 if (element_names.Contains (element_initializer.Name)) {
12021 ec.Report.Error (1912, element_initializer.Location,
12022 "An object initializer includes more than one member `{0}' initialization",
12023 element_initializer.Name);
12025 element_names.Add (element_initializer.Name);
12030 Expression e = initializer.Resolve (ec);
12031 if (e == EmptyExpressionStatement.Instance)
12032 initializers.RemoveAt (i--);
12034 initializers [i] = e;
12037 type = ec.CurrentInitializerVariable.Type;
12038 if (is_collection_initialization) {
12039 if (TypeManager.HasElementType (type)) {
12040 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12041 type.GetSignatureForError ());
12045 eclass = ExprClass.Variable;
12049 public override void Emit (EmitContext ec)
12051 EmitStatement (ec);
12054 public override void EmitStatement (EmitContext ec)
12056 foreach (ExpressionStatement e in initializers) {
12057 // TODO: need location region
12058 ec.Mark (e.Location);
12059 e.EmitStatement (ec);
12063 public override void FlowAnalysis (FlowAnalysisContext fc)
12065 foreach (var initializer in initializers) {
12066 if (initializer != null)
12067 initializer.FlowAnalysis (fc);
12073 // New expression with element/object initializers
12075 public class NewInitialize : New
12078 // This class serves as a proxy for variable initializer target instances.
12079 // A real variable is assigned later when we resolve left side of an
12082 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12084 NewInitialize new_instance;
12086 public InitializerTargetExpression (NewInitialize newInstance)
12088 this.type = newInstance.type;
12089 this.loc = newInstance.loc;
12090 this.eclass = newInstance.eclass;
12091 this.new_instance = newInstance;
12094 public override bool ContainsEmitWithAwait ()
12099 public override Expression CreateExpressionTree (ResolveContext ec)
12101 // Should not be reached
12102 throw new NotSupportedException ("ET");
12105 protected override Expression DoResolve (ResolveContext ec)
12110 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12115 public override void Emit (EmitContext ec)
12117 Expression e = (Expression) new_instance.instance;
12121 public override Expression EmitToField (EmitContext ec)
12123 return (Expression) new_instance.instance;
12126 #region IMemoryLocation Members
12128 public void AddressOf (EmitContext ec, AddressOp mode)
12130 new_instance.instance.AddressOf (ec, mode);
12136 CollectionOrObjectInitializers initializers;
12137 IMemoryLocation instance;
12138 DynamicExpressionStatement dynamic;
12140 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12141 : base (requested_type, arguments, l)
12143 this.initializers = initializers;
12146 public CollectionOrObjectInitializers Initializers {
12148 return initializers;
12152 protected override void CloneTo (CloneContext clonectx, Expression t)
12154 base.CloneTo (clonectx, t);
12156 NewInitialize target = (NewInitialize) t;
12157 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12160 public override bool ContainsEmitWithAwait ()
12162 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12165 public override Expression CreateExpressionTree (ResolveContext ec)
12167 Arguments args = new Arguments (2);
12168 args.Add (new Argument (base.CreateExpressionTree (ec)));
12169 if (!initializers.IsEmpty)
12170 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12172 return CreateExpressionFactoryCall (ec,
12173 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12177 protected override Expression DoResolve (ResolveContext ec)
12179 Expression e = base.DoResolve (ec);
12183 if (type.IsDelegate) {
12184 ec.Report.Error (1958, Initializers.Location,
12185 "Object and collection initializers cannot be used to instantiate a delegate");
12188 Expression previous = ec.CurrentInitializerVariable;
12189 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12190 initializers.Resolve (ec);
12191 ec.CurrentInitializerVariable = previous;
12193 dynamic = e as DynamicExpressionStatement;
12194 if (dynamic != null)
12200 public override void Emit (EmitContext ec)
12202 if (!CanEmitOptimizedLocalTarget (ec)) {
12203 var fe = ec.GetTemporaryField (type);
12205 if (!Emit (ec, fe))
12214 public override bool Emit (EmitContext ec, IMemoryLocation target)
12217 // Expression is initialized into temporary target then moved
12218 // to real one for atomicity
12220 IMemoryLocation temp_target = target;
12222 LocalTemporary temp = null;
12223 bool by_ref = false;
12224 if (!initializers.IsEmpty) {
12225 temp_target = target as LocalTemporary;
12226 if (temp_target == null)
12227 temp_target = target as StackFieldExpr;
12229 if (temp_target == null) {
12230 var vr = target as VariableReference;
12231 if (vr != null && vr.IsRef) {
12237 if (temp_target == null)
12238 temp_target = temp = new LocalTemporary (type);
12241 bool left_on_stack;
12242 if (dynamic != null) {
12244 left_on_stack = true;
12246 left_on_stack = base.Emit (ec, temp_target);
12249 if (initializers.IsEmpty)
12250 return left_on_stack;
12252 StackFieldExpr sf = null;
12254 // Move a new instance (reference-type) to local temporary variable
12255 if (left_on_stack) {
12257 temp_target = temp = new LocalTemporary (type);
12263 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12265 throw new NotImplementedException ();
12267 sf = ec.GetTemporaryField (type);
12268 sf.AutomaticallyReuse = false;
12269 sf.EmitAssign (ec, temp, false, false);
12272 left_on_stack = false;
12276 instance = temp_target;
12278 initializers.Emit (ec);
12280 ((Expression)temp_target).Emit (ec);
12286 sf.PrepareCleanup (ec);
12291 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12293 return !(method == null && TypeSpec.IsValueType (type) &&
12294 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12295 initializers.ContainsEmitWithAwait ());
12298 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12300 instance = base.EmitAddressOf (ec, Mode);
12302 if (!initializers.IsEmpty)
12303 initializers.Emit (ec);
12308 public override void FlowAnalysis (FlowAnalysisContext fc)
12310 base.FlowAnalysis (fc);
12311 initializers.FlowAnalysis (fc);
12314 public override object Accept (StructuralVisitor visitor)
12316 return visitor.Visit (this);
12320 public class NewAnonymousType : New
12322 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12324 List<AnonymousTypeParameter> parameters;
12325 readonly TypeContainer parent;
12326 AnonymousTypeClass anonymous_type;
12328 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12329 : base (null, null, loc)
12331 this.parameters = parameters;
12332 this.parent = parent;
12335 public List<AnonymousTypeParameter> Parameters {
12337 return this.parameters;
12341 protected override void CloneTo (CloneContext clonectx, Expression target)
12343 if (parameters == null)
12346 NewAnonymousType t = (NewAnonymousType) target;
12347 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12348 foreach (AnonymousTypeParameter atp in parameters)
12349 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12352 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12354 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12358 type = AnonymousTypeClass.Create (parent, parameters, loc);
12362 int errors = ec.Report.Errors;
12363 type.CreateContainer ();
12364 type.DefineContainer ();
12365 type.ExpandBaseInterfaces ();
12367 if ((ec.Report.Errors - errors) == 0) {
12368 parent.Module.AddAnonymousType (type);
12369 type.PrepareEmit ();
12375 public override Expression CreateExpressionTree (ResolveContext ec)
12377 if (parameters == null)
12378 return base.CreateExpressionTree (ec);
12380 var init = new ArrayInitializer (parameters.Count, loc);
12381 foreach (var m in anonymous_type.Members) {
12382 var p = m as Property;
12384 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12387 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12388 foreach (Argument a in arguments)
12389 ctor_args.Add (a.CreateExpressionTree (ec));
12391 Arguments args = new Arguments (3);
12392 args.Add (new Argument (new TypeOfMethod (method, loc)));
12393 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12394 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12396 return CreateExpressionFactoryCall (ec, "New", args);
12399 protected override Expression DoResolve (ResolveContext ec)
12401 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12402 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12406 if (parameters == null) {
12407 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12408 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12409 return base.DoResolve (ec);
12412 bool error = false;
12413 arguments = new Arguments (parameters.Count);
12414 var t_args = new TypeSpec [parameters.Count];
12415 for (int i = 0; i < parameters.Count; ++i) {
12416 Expression e = parameters [i].Resolve (ec);
12422 arguments.Add (new Argument (e));
12423 t_args [i] = e.Type;
12429 anonymous_type = CreateAnonymousType (ec, parameters);
12430 if (anonymous_type == null)
12433 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12434 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12435 eclass = ExprClass.Value;
12439 public override object Accept (StructuralVisitor visitor)
12441 return visitor.Visit (this);
12445 public class AnonymousTypeParameter : ShimExpression
12447 public readonly string Name;
12449 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12450 : base (initializer)
12456 public AnonymousTypeParameter (Parameter parameter)
12457 : base (new SimpleName (parameter.Name, parameter.Location))
12459 this.Name = parameter.Name;
12460 this.loc = parameter.Location;
12463 public override bool Equals (object o)
12465 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12466 return other != null && Name == other.Name;
12469 public override int GetHashCode ()
12471 return Name.GetHashCode ();
12474 protected override Expression DoResolve (ResolveContext ec)
12476 Expression e = expr.Resolve (ec);
12480 if (e.eclass == ExprClass.MethodGroup) {
12481 Error_InvalidInitializer (ec, e.ExprClassName);
12486 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12487 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12494 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12496 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12497 Name, initializer);
12501 public class CatchFilterExpression : BooleanExpression
12503 public CatchFilterExpression (Expression expr, Location loc)
12510 public class InterpolatedString : Expression
12512 readonly StringLiteral start, end;
12513 List<Expression> interpolations;
12514 Arguments arguments;
12516 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12518 this.start = start;
12520 this.interpolations = interpolations;
12521 loc = start.Location;
12524 protected override void CloneTo (CloneContext clonectx, Expression t)
12526 InterpolatedString target = (InterpolatedString) t;
12528 if (interpolations != null) {
12529 target.interpolations = new List<Expression> ();
12530 foreach (var interpolation in interpolations) {
12531 target.interpolations.Add (interpolation.Clone (clonectx));
12536 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12538 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12539 if (factory == null)
12542 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12543 var res = new Invocation (ma, arguments).Resolve (rc);
12544 if (res != null && res.Type != type)
12545 res = Convert.ExplicitConversion (rc, res, type, loc);
12550 public override bool ContainsEmitWithAwait ()
12552 if (interpolations == null)
12555 foreach (var expr in interpolations) {
12556 if (expr.ContainsEmitWithAwait ())
12563 public override Expression CreateExpressionTree (ResolveContext rc)
12565 var best = ResolveBestFormatOverload (rc);
12569 Expression instance = new NullLiteral (loc);
12570 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12571 return CreateExpressionFactoryCall (rc, "Call", args);
12574 protected override Expression DoResolve (ResolveContext rc)
12578 if (interpolations == null) {
12580 arguments = new Arguments (1);
12582 arguments = new Arguments (interpolations.Count);
12584 var sb = new StringBuilder (start.Value);
12585 for (int i = 0; i < interpolations.Count; ++i) {
12587 sb.Append ('{').Append (i / 2);
12588 var isi = (InterpolatedStringInsert)interpolations [i];
12589 if (isi.Alignment != null) {
12591 var value = isi.ResolveAligment (rc);
12593 sb.Append (value.Value);
12596 if (isi.Format != null) {
12598 sb.Append (isi.Format);
12602 arguments.Add (new Argument (isi.Resolve (rc)));
12604 sb.Append (((StringLiteral)interpolations [i]).Value);
12608 sb.Append (end.Value);
12609 str = sb.ToString ();
12612 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12614 eclass = ExprClass.Value;
12615 type = rc.BuiltinTypes.String;
12619 public override void Emit (EmitContext ec)
12621 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12622 if (interpolations == null) {
12623 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12624 if (str != start.Value)
12625 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12632 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12636 var ca = new CallEmitter ();
12637 ca.Emit (ec, best, arguments, loc);
12640 public override void FlowAnalysis (FlowAnalysisContext fc)
12642 if (interpolations != null) {
12643 foreach (var expr in interpolations) {
12644 expr.FlowAnalysis (fc);
12649 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12651 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12652 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12653 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12657 public class InterpolatedStringInsert : CompositeExpression
12659 public InterpolatedStringInsert (Expression expr)
12664 public Expression Alignment { get; set; }
12665 public string Format { get; set; }
12667 protected override void CloneTo (CloneContext clonectx, Expression t)
12669 var target = (InterpolatedStringInsert)t;
12670 target.expr = expr.Clone (clonectx);
12671 if (Alignment != null)
12672 target.Alignment = Alignment.Clone (clonectx);
12675 protected override Expression DoResolve (ResolveContext rc)
12677 var expr = base.DoResolve (rc);
12682 // For better error reporting, assumes the built-in implementation uses object
12685 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12688 public override void FlowAnalysis (FlowAnalysisContext fc)
12690 Child.FlowAnalysis (fc);
12693 public int? ResolveAligment (ResolveContext rc)
12695 var c = Alignment.ResolveLabelConstant (rc);
12699 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12703 var value = (int) c.GetValueAsLong ();
12704 if (value > 32767 || value < -32767) {
12705 rc.Report.Warning (8094, 1, Alignment.Location,
12706 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");