2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
722 UnsafeError (ec, loc);
724 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
725 if (Expr == null || Expr.eclass != ExprClass.Variable) {
726 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
730 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
734 IVariableReference vr = Expr as IVariableReference;
737 is_fixed = vr.IsFixed;
738 vr.SetHasAddressTaken ();
741 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
744 IFixedExpression fe = Expr as IFixedExpression;
745 is_fixed = fe != null && fe.IsFixed;
748 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
749 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
752 type = PointerContainer.MakeType (ec.Module, Expr.Type);
753 eclass = ExprClass.Value;
757 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
759 expr = DoNumericPromotion (rc, Oper, expr);
760 TypeSpec expr_type = expr.Type;
761 foreach (TypeSpec t in predefined) {
769 // Perform user-operator overload resolution
771 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
773 CSharp.Operator.OpType op_type;
775 case Operator.LogicalNot:
776 op_type = CSharp.Operator.OpType.LogicalNot; break;
777 case Operator.OnesComplement:
778 op_type = CSharp.Operator.OpType.OnesComplement; break;
779 case Operator.UnaryNegation:
780 op_type = CSharp.Operator.OpType.UnaryNegation; break;
781 case Operator.UnaryPlus:
782 op_type = CSharp.Operator.OpType.UnaryPlus; break;
784 throw new InternalErrorException (Oper.ToString ());
787 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
791 Arguments args = new Arguments (1);
792 args.Add (new Argument (expr));
794 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
795 var oper = res.ResolveOperator (ec, ref args);
800 Expr = args [0].Expr;
801 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
805 // Unary user type overload resolution
807 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
809 Expression best_expr = ResolveUserOperator (ec, expr);
810 if (best_expr != null)
813 foreach (TypeSpec t in predefined) {
814 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
815 if (oper_expr == null)
818 if (oper_expr == ErrorExpression.Instance)
822 // decimal type is predefined but has user-operators
824 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
825 oper_expr = ResolveUserType (ec, oper_expr, predefined);
827 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
829 if (oper_expr == null)
832 if (best_expr == null) {
833 best_expr = oper_expr;
837 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
839 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
840 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
842 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
849 best_expr = oper_expr;
852 if (best_expr == null)
856 // HACK: Decimal user-operator is included in standard operators
858 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
862 type = best_expr.Type;
866 protected override void CloneTo (CloneContext clonectx, Expression t)
868 Unary target = (Unary) t;
870 target.Expr = Expr.Clone (clonectx);
873 public override object Accept (StructuralVisitor visitor)
875 return visitor.Visit (this);
881 // Unary operators are turned into Indirection expressions
882 // after semantic analysis (this is so we can take the address
883 // of an indirection).
885 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
887 LocalTemporary temporary;
890 public Indirection (Expression expr, Location l)
896 public Expression Expr {
902 public bool IsFixed {
906 public override Location StartLocation {
908 return expr.StartLocation;
912 protected override void CloneTo (CloneContext clonectx, Expression t)
914 Indirection target = (Indirection) t;
915 target.expr = expr.Clone (clonectx);
918 public override bool ContainsEmitWithAwait ()
920 throw new NotImplementedException ();
923 public override Expression CreateExpressionTree (ResolveContext ec)
925 Error_PointerInsideExpressionTree (ec);
929 public override void Emit (EmitContext ec)
934 ec.EmitLoadFromPtr (Type);
937 public void Emit (EmitContext ec, bool leave_copy)
941 ec.Emit (OpCodes.Dup);
942 temporary = new LocalTemporary (expr.Type);
943 temporary.Store (ec);
947 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
949 prepared = isCompound;
954 ec.Emit (OpCodes.Dup);
958 ec.Emit (OpCodes.Dup);
959 temporary = new LocalTemporary (source.Type);
960 temporary.Store (ec);
963 ec.EmitStoreFromPtr (type);
965 if (temporary != null) {
967 temporary.Release (ec);
971 public void AddressOf (EmitContext ec, AddressOp Mode)
976 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
978 return DoResolve (ec);
981 protected override Expression DoResolve (ResolveContext ec)
983 expr = expr.Resolve (ec);
988 UnsafeError (ec, loc);
990 var pc = expr.Type as PointerContainer;
993 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
999 if (type.Kind == MemberKind.Void) {
1000 Error_VoidPointerOperation (ec);
1004 eclass = ExprClass.Variable;
1008 public override object Accept (StructuralVisitor visitor)
1010 return visitor.Visit (this);
1015 /// Unary Mutator expressions (pre and post ++ and --)
1019 /// UnaryMutator implements ++ and -- expressions. It derives from
1020 /// ExpressionStatement becuase the pre/post increment/decrement
1021 /// operators can be used in a statement context.
1023 /// FIXME: Idea, we could split this up in two classes, one simpler
1024 /// for the common case, and one with the extra fields for more complex
1025 /// classes (indexers require temporary access; overloaded require method)
1028 public class UnaryMutator : ExpressionStatement
1030 class DynamicPostMutator : Expression, IAssignMethod
1032 LocalTemporary temp;
1035 public DynamicPostMutator (Expression expr)
1038 this.type = expr.Type;
1039 this.loc = expr.Location;
1042 public override Expression CreateExpressionTree (ResolveContext ec)
1044 throw new NotImplementedException ("ET");
1047 protected override Expression DoResolve (ResolveContext rc)
1049 eclass = expr.eclass;
1053 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1055 expr.DoResolveLValue (ec, right_side);
1056 return DoResolve (ec);
1059 public override void Emit (EmitContext ec)
1064 public void Emit (EmitContext ec, bool leave_copy)
1066 throw new NotImplementedException ();
1070 // Emits target assignment using unmodified source value
1072 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1075 // Allocate temporary variable to keep original value before it's modified
1077 temp = new LocalTemporary (type);
1081 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1092 public enum Mode : byte {
1099 PreDecrement = IsDecrement,
1100 PostIncrement = IsPost,
1101 PostDecrement = IsPost | IsDecrement
1105 bool is_expr, recurse;
1107 protected Expression expr;
1109 // Holds the real operation
1110 Expression operation;
1112 public UnaryMutator (Mode m, Expression e, Location loc)
1119 public Mode UnaryMutatorMode {
1125 public Expression Expr {
1131 public override Location StartLocation {
1133 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1137 public override bool ContainsEmitWithAwait ()
1139 return expr.ContainsEmitWithAwait ();
1142 public override Expression CreateExpressionTree (ResolveContext ec)
1144 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1147 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1150 // Predefined ++ and -- operators exist for the following types:
1151 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1153 return new TypeSpec[] {
1169 protected override Expression DoResolve (ResolveContext ec)
1171 expr = expr.Resolve (ec);
1173 if (expr == null || expr.Type == InternalType.ErrorType)
1176 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1178 // Handle postfix unary operators using local
1179 // temporary variable
1181 if ((mode & Mode.IsPost) != 0)
1182 expr = new DynamicPostMutator (expr);
1184 Arguments args = new Arguments (1);
1185 args.Add (new Argument (expr));
1186 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1189 if (expr.Type.IsNullableType)
1190 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1192 return DoResolveOperation (ec);
1195 protected Expression DoResolveOperation (ResolveContext ec)
1197 eclass = ExprClass.Value;
1200 if (expr is RuntimeValueExpression) {
1203 // Use itself at the top of the stack
1204 operation = new EmptyExpression (type);
1208 // The operand of the prefix/postfix increment decrement operators
1209 // should be an expression that is classified as a variable,
1210 // a property access or an indexer access
1212 // TODO: Move to parser, expr is ATypeNameExpression
1213 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1214 expr = expr.ResolveLValue (ec, expr);
1216 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1220 // Step 1: Try to find a user operator, it has priority over predefined ones
1222 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1223 var methods = MemberCache.GetUserOperator (type, user_op, false);
1225 if (methods != null) {
1226 Arguments args = new Arguments (1);
1227 args.Add (new Argument (expr));
1229 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1230 var method = res.ResolveOperator (ec, ref args);
1234 args[0].Expr = operation;
1235 operation = new UserOperatorCall (method, args, null, loc);
1236 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1241 // Step 2: Try predefined types
1244 Expression source = null;
1245 bool primitive_type;
1248 // Predefined without user conversion first for speed-up
1250 // Predefined ++ and -- operators exist for the following types:
1251 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1253 switch (type.BuiltinType) {
1254 case BuiltinTypeSpec.Type.Byte:
1255 case BuiltinTypeSpec.Type.SByte:
1256 case BuiltinTypeSpec.Type.Short:
1257 case BuiltinTypeSpec.Type.UShort:
1258 case BuiltinTypeSpec.Type.Int:
1259 case BuiltinTypeSpec.Type.UInt:
1260 case BuiltinTypeSpec.Type.Long:
1261 case BuiltinTypeSpec.Type.ULong:
1262 case BuiltinTypeSpec.Type.Char:
1263 case BuiltinTypeSpec.Type.Float:
1264 case BuiltinTypeSpec.Type.Double:
1265 case BuiltinTypeSpec.Type.Decimal:
1267 primitive_type = true;
1270 primitive_type = false;
1272 // ++/-- on pointer variables of all types except void*
1273 if (type.IsPointer) {
1274 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1275 Error_VoidPointerOperation (ec);
1281 Expression best_source = null;
1282 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1283 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1285 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1289 if (best_source == null) {
1290 best_source = source;
1294 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1299 best_source = source;
1303 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1307 source = best_source;
1310 // ++/-- on enum types
1311 if (source == null && type.IsEnum)
1314 if (source == null) {
1315 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1322 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1323 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1324 operation = new Binary (op, source, one);
1325 operation = operation.Resolve (ec);
1326 if (operation == null)
1327 throw new NotImplementedException ("should not be reached");
1329 if (operation.Type != type) {
1331 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1333 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1339 void EmitCode (EmitContext ec, bool is_expr)
1342 this.is_expr = is_expr;
1343 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1346 public override void Emit (EmitContext ec)
1349 // We use recurse to allow ourselfs to be the source
1350 // of an assignment. This little hack prevents us from
1351 // having to allocate another expression
1354 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1362 EmitCode (ec, true);
1365 protected virtual void EmitOperation (EmitContext ec)
1367 operation.Emit (ec);
1370 public override void EmitStatement (EmitContext ec)
1372 EmitCode (ec, false);
1375 public override void FlowAnalysis (FlowAnalysisContext fc)
1377 expr.FlowAnalysis (fc);
1381 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1383 string GetOperatorExpressionTypeName ()
1385 return IsDecrement ? "Decrement" : "Increment";
1389 get { return (mode & Mode.IsDecrement) != 0; }
1393 public override SLE.Expression MakeExpression (BuilderContext ctx)
1395 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1396 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1397 return SLE.Expression.Assign (target, source);
1400 public static string OperName (Mode oper)
1402 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1405 protected override void CloneTo (CloneContext clonectx, Expression t)
1407 UnaryMutator target = (UnaryMutator) t;
1409 target.expr = expr.Clone (clonectx);
1412 public override object Accept (StructuralVisitor visitor)
1414 return visitor.Visit (this);
1420 // Base class for the `is' and `as' operators
1422 public abstract class Probe : Expression
1424 public Expression ProbeType;
1425 protected Expression expr;
1426 protected TypeSpec probe_type_expr;
1428 protected Probe (Expression expr, Expression probe_type, Location l)
1430 ProbeType = probe_type;
1435 public Expression Expr {
1441 public override bool ContainsEmitWithAwait ()
1443 return expr.ContainsEmitWithAwait ();
1446 protected Expression ResolveCommon (ResolveContext rc)
1448 expr = expr.Resolve (rc);
1452 ResolveProbeType (rc);
1453 if (probe_type_expr == null)
1456 if (probe_type_expr.IsStatic) {
1457 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1458 probe_type_expr.GetSignatureForError ());
1462 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1463 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1468 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1469 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1477 protected virtual void ResolveProbeType (ResolveContext rc)
1479 probe_type_expr = ProbeType.ResolveAsType (rc);
1482 public override void EmitSideEffect (EmitContext ec)
1484 expr.EmitSideEffect (ec);
1487 public override void FlowAnalysis (FlowAnalysisContext fc)
1489 expr.FlowAnalysis (fc);
1492 public override bool HasConditionalAccess ()
1494 return expr.HasConditionalAccess ();
1497 protected abstract string OperatorName { get; }
1499 protected override void CloneTo (CloneContext clonectx, Expression t)
1501 Probe target = (Probe) t;
1503 target.expr = expr.Clone (clonectx);
1504 target.ProbeType = ProbeType.Clone (clonectx);
1510 /// Implementation of the `is' operator.
1512 public class Is : Probe
1514 Nullable.Unwrap expr_unwrap;
1515 MethodSpec number_mg;
1516 Arguments number_args;
1518 public Is (Expression expr, Expression probe_type, Location l)
1519 : base (expr, probe_type, l)
1523 protected override string OperatorName {
1524 get { return "is"; }
1527 public LocalVariable Variable { get; set; }
1529 public override Expression CreateExpressionTree (ResolveContext ec)
1531 if (Variable != null)
1532 throw new NotSupportedException ();
1534 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1535 expr.CreateExpressionTree (ec),
1536 new TypeOf (probe_type_expr, loc));
1538 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1541 Expression CreateConstantResult (ResolveContext rc, bool result)
1544 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1545 probe_type_expr.GetSignatureForError ());
1547 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1548 probe_type_expr.GetSignatureForError ());
1550 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1551 return expr.IsSideEffectFree ?
1552 ReducedExpression.Create (c, this) :
1553 new SideEffectConstant (c, this, loc);
1556 public override void Emit (EmitContext ec)
1558 if (probe_type_expr == null) {
1559 if (ProbeType is WildcardPattern) {
1560 expr.EmitSideEffect (ec);
1561 ProbeType.Emit (ec);
1563 EmitPatternMatch (ec);
1570 if (expr_unwrap == null) {
1572 ec.Emit (OpCodes.Cgt_Un);
1576 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1578 if (probe_type_expr == null) {
1579 EmitPatternMatch (ec);
1584 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1587 void EmitPatternMatch (EmitContext ec)
1589 var no_match = ec.DefineLabel ();
1590 var end = ec.DefineLabel ();
1592 if (expr_unwrap != null) {
1593 expr_unwrap.EmitCheck (ec);
1595 if (ProbeType.IsNull) {
1597 ec.Emit (OpCodes.Ceq);
1601 ec.Emit (OpCodes.Brfalse_S, no_match);
1602 expr_unwrap.Emit (ec);
1603 ProbeType.Emit (ec);
1604 ec.Emit (OpCodes.Ceq);
1605 ec.Emit (OpCodes.Br_S, end);
1606 ec.MarkLabel (no_match);
1612 if (number_args != null && number_args.Count == 3) {
1613 var ce = new CallEmitter ();
1614 ce.Emit (ec, number_mg, number_args, loc);
1618 var probe_type = ProbeType.Type;
1621 ec.Emit (OpCodes.Isinst, probe_type);
1622 ec.Emit (OpCodes.Dup);
1623 ec.Emit (OpCodes.Brfalse, no_match);
1625 bool complex_pattern = ProbeType is ComplexPatternExpression;
1626 Label prev = ec.RecursivePatternLabel;
1627 if (complex_pattern)
1628 ec.RecursivePatternLabel = ec.DefineLabel ();
1630 if (number_mg != null) {
1631 var ce = new CallEmitter ();
1632 ce.Emit (ec, number_mg, number_args, loc);
1634 if (TypeSpec.IsValueType (probe_type))
1635 ec.Emit (OpCodes.Unbox_Any, probe_type);
1637 ProbeType.Emit (ec);
1638 if (complex_pattern) {
1641 ec.Emit (OpCodes.Ceq);
1644 ec.Emit (OpCodes.Br_S, end);
1645 ec.MarkLabel (no_match);
1647 ec.Emit (OpCodes.Pop);
1649 if (complex_pattern)
1650 ec.MarkLabel (ec.RecursivePatternLabel);
1652 ec.RecursivePatternLabel = prev;
1658 void EmitLoad (EmitContext ec)
1660 Label no_value_label = new Label ();
1662 if (expr_unwrap != null) {
1663 expr_unwrap.EmitCheck (ec);
1665 if (Variable == null)
1668 ec.Emit (OpCodes.Dup);
1669 no_value_label = ec.DefineLabel ();
1670 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1671 expr_unwrap.Emit (ec);
1675 // Only to make verifier happy
1676 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1677 ec.Emit (OpCodes.Box, expr.Type);
1679 ec.Emit (OpCodes.Isinst, probe_type_expr);
1682 if (Variable != null) {
1683 bool value_on_stack;
1684 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1685 ec.Emit (OpCodes.Dup);
1686 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1687 value_on_stack = true;
1689 value_on_stack = false;
1692 Variable.CreateBuilder (ec);
1693 Variable.EmitAssign (ec);
1695 if (expr_unwrap != null) {
1696 ec.MarkLabel (no_value_label);
1697 } else if (!value_on_stack) {
1703 protected override Expression DoResolve (ResolveContext rc)
1705 if (ResolveCommon (rc) == null)
1708 type = rc.BuiltinTypes.Bool;
1709 eclass = ExprClass.Value;
1711 if (probe_type_expr == null)
1712 return ResolveMatchingExpression (rc);
1714 var res = ResolveResultExpression (rc);
1715 if (Variable != null) {
1716 if (res is Constant)
1717 throw new NotImplementedException ("constant in type pattern matching");
1719 Variable.Type = probe_type_expr;
1720 var bc = rc as BlockContext;
1722 Variable.PrepareAssignmentAnalysis (bc);
1728 public override void FlowAnalysis (FlowAnalysisContext fc)
1730 base.FlowAnalysis (fc);
1732 if (Variable != null)
1733 fc.SetVariableAssigned (Variable.VariableInfo, true);
1736 protected override void ResolveProbeType (ResolveContext rc)
1738 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1739 if (ProbeType is PatternExpression) {
1740 ProbeType.Resolve (rc);
1745 // Have to use session recording because we don't have reliable type probing
1746 // mechanism (similar issue as in attributes resolving)
1748 // TODO: This is still wrong because ResolveAsType can be destructive
1750 var type_printer = new SessionReportPrinter ();
1751 var prev_recorder = rc.Report.SetPrinter (type_printer);
1753 probe_type_expr = ProbeType.ResolveAsType (rc);
1754 type_printer.EndSession ();
1756 if (probe_type_expr != null) {
1757 type_printer.Merge (rc.Report.Printer);
1758 rc.Report.SetPrinter (prev_recorder);
1762 var vexpr = ProbeType as VarExpr;
1763 if (vexpr != null && vexpr.InferType (rc, expr)) {
1764 probe_type_expr = vexpr.Type;
1765 rc.Report.SetPrinter (prev_recorder);
1769 var expr_printer = new SessionReportPrinter ();
1770 rc.Report.SetPrinter (expr_printer);
1771 ProbeType = ProbeType.Resolve (rc);
1772 expr_printer.EndSession ();
1774 if (ProbeType != null) {
1775 expr_printer.Merge (rc.Report.Printer);
1777 type_printer.Merge (rc.Report.Printer);
1780 rc.Report.SetPrinter (prev_recorder);
1784 base.ResolveProbeType (rc);
1787 Expression ResolveMatchingExpression (ResolveContext rc)
1789 var mc = ProbeType as Constant;
1791 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1792 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1797 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1799 var c = Expr as Constant;
1801 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1806 if (Expr.Type.IsNullableType) {
1807 expr_unwrap = new Nullable.Unwrap (Expr);
1808 expr_unwrap.Resolve (rc);
1809 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1810 } else if (ProbeType.Type == Expr.Type) {
1811 // TODO: Better error handling
1812 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1813 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1814 var helper = rc.Module.CreatePatterMatchingHelper ();
1815 number_mg = helper.NumberMatcher.Spec;
1818 // There are actually 3 arguments but the first one is already on the stack
1820 number_args = new Arguments (3);
1821 if (!ProbeType.Type.IsEnum)
1822 number_args.Add (new Argument (Expr));
1824 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1825 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1831 if (ProbeType is PatternExpression) {
1832 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1833 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1839 // TODO: Better error message
1840 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1844 Expression ResolveResultExpression (ResolveContext ec)
1846 TypeSpec d = expr.Type;
1847 bool d_is_nullable = false;
1850 // If E is a method group or the null literal, or if the type of E is a reference
1851 // type or a nullable type and the value of E is null, the result is false
1853 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1854 return CreateConstantResult (ec, false);
1856 if (d.IsNullableType) {
1857 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1858 if (!ut.IsGenericParameter) {
1860 d_is_nullable = true;
1864 TypeSpec t = probe_type_expr;
1865 bool t_is_nullable = false;
1866 if (t.IsNullableType) {
1867 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1868 if (!ut.IsGenericParameter) {
1870 t_is_nullable = true;
1877 // D and T are the same value types but D can be null
1879 if (d_is_nullable && !t_is_nullable) {
1880 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1885 // The result is true if D and T are the same value types
1887 return CreateConstantResult (ec, true);
1890 var tp = d as TypeParameterSpec;
1892 return ResolveGenericParameter (ec, t, tp);
1895 // An unboxing conversion exists
1897 if (Convert.ExplicitReferenceConversionExists (d, t))
1901 // open generic type
1903 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1906 var tps = t as TypeParameterSpec;
1908 return ResolveGenericParameter (ec, d, tps);
1910 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1911 ec.Report.Warning (1981, 3, loc,
1912 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1913 OperatorName, t.GetSignatureForError ());
1916 if (TypeManager.IsGenericParameter (d))
1917 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1919 if (TypeSpec.IsValueType (d)) {
1920 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1921 if (d_is_nullable && !t_is_nullable) {
1922 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1926 return CreateConstantResult (ec, true);
1929 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1930 var c = expr as Constant;
1932 return CreateConstantResult (ec, !c.IsNull);
1935 // Do not optimize for imported type or dynamic type
1937 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1938 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1942 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1946 // Turn is check into simple null check for implicitly convertible reference types
1948 return ReducedExpression.Create (
1949 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1953 if (Convert.ExplicitReferenceConversionExists (d, t))
1957 // open generic type
1959 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1964 return CreateConstantResult (ec, false);
1967 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1969 if (t.IsReferenceType) {
1971 return CreateConstantResult (ec, false);
1974 if (expr.Type.IsGenericParameter) {
1975 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1976 return CreateConstantResult (ec, true);
1978 expr = new BoxedCast (expr, d);
1984 public override object Accept (StructuralVisitor visitor)
1986 return visitor.Visit (this);
1990 class WildcardPattern : PatternExpression
1992 public WildcardPattern (Location loc)
1997 protected override Expression DoResolve (ResolveContext rc)
1999 eclass = ExprClass.Value;
2000 type = rc.BuiltinTypes.Object;
2004 public override void Emit (EmitContext ec)
2010 class RecursivePattern : ComplexPatternExpression
2012 MethodGroupExpr operator_mg;
2013 Arguments operator_args;
2015 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2016 : base (typeExpresion, loc)
2018 Arguments = arguments;
2021 public Arguments Arguments { get; private set; }
2023 protected override Expression DoResolve (ResolveContext rc)
2025 type = TypeExpression.ResolveAsType (rc);
2029 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2030 if (operators == null) {
2031 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2035 var ops = FindMatchingOverloads (operators);
2037 // TODO: better error message
2038 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2043 Arguments.Resolve (rc, out dynamic_args);
2045 throw new NotImplementedException ("dynamic argument");
2047 var op = FindBestOverload (rc, ops);
2049 // TODO: better error message
2050 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2054 var op_types = op.Parameters.Types;
2055 operator_args = new Arguments (op_types.Length);
2056 operator_args.Add (new Argument (new EmptyExpression (type)));
2058 for (int i = 0; i < Arguments.Count; ++i) {
2059 // TODO: Needs releasing optimization
2060 var lt = new LocalTemporary (op_types [i + 1]);
2061 operator_args.Add (new Argument (lt, Argument.AType.Out));
2063 if (comparisons == null)
2064 comparisons = new Expression[Arguments.Count];
2069 var arg = Arguments [i];
2070 var named = arg as NamedArgument;
2071 if (named != null) {
2072 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2073 expr = Arguments [arg_comp_index].Expr;
2079 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2082 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2084 eclass = ExprClass.Value;
2088 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2090 int arg_count = Arguments.Count + 1;
2091 List<MethodSpec> best = null;
2092 foreach (MethodSpec method in members) {
2093 var pm = method.Parameters;
2094 if (pm.Count != arg_count)
2097 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2099 for (int ii = 1; ii < pm.Count; ++ii) {
2100 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2110 best = new List<MethodSpec> ();
2118 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2120 for (int ii = 0; ii < Arguments.Count; ++ii) {
2121 var arg = Arguments [ii];
2122 var expr = arg.Expr;
2123 if (expr is WildcardPattern)
2126 var na = arg as NamedArgument;
2127 for (int i = 0; i < methods.Count; ++i) {
2128 var pd = methods [i].Parameters;
2132 index = pd.GetParameterIndexByName (na.Name);
2134 methods.RemoveAt (i--);
2141 var m = pd.Types [index];
2142 if (!Convert.ImplicitConversionExists (rc, expr, m))
2143 methods.RemoveAt (i--);
2147 if (methods.Count != 1)
2153 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2155 operator_mg.EmitCall (ec, operator_args, false);
2156 ec.Emit (OpCodes.Brfalse, target);
2158 base.EmitBranchable (ec, target, on_true);
2161 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2163 if (expr is WildcardPattern)
2164 return new EmptyExpression (expr.Type);
2166 var recursive = expr as RecursivePattern;
2167 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2171 if (recursive != null) {
2172 recursive.SetParentInstance (lt);
2176 // TODO: Better error handling
2177 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2180 public void SetParentInstance (Expression instance)
2182 operator_args [0] = new Argument (instance);
2186 class PropertyPattern : ComplexPatternExpression
2188 LocalTemporary instance;
2190 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2191 : base (typeExpresion, loc)
2196 public List<PropertyPatternMember> Members { get; private set; }
2198 protected override Expression DoResolve (ResolveContext rc)
2200 type = TypeExpression.ResolveAsType (rc);
2204 comparisons = new Expression[Members.Count];
2206 // TODO: optimize when source is VariableReference, it'd save dup+pop
2207 instance = new LocalTemporary (type);
2209 for (int i = 0; i < Members.Count; i++) {
2210 var lookup = Members [i];
2212 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2213 if (member == null) {
2214 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2215 if (member != null) {
2216 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2221 if (member == null) {
2222 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2226 var pe = member as PropertyExpr;
2227 if (pe == null || member is FieldExpr) {
2228 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2232 // TODO: Obsolete checks
2233 // TODO: check accessibility
2234 if (pe != null && !pe.PropertyInfo.HasGet) {
2235 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2239 var expr = lookup.Expr.Resolve (rc);
2243 var me = (MemberExpr)member;
2244 me.InstanceExpression = instance;
2246 comparisons [i] = ResolveComparison (rc, expr, me);
2249 eclass = ExprClass.Value;
2253 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2255 if (expr is WildcardPattern)
2256 return new EmptyExpression (expr.Type);
2258 return new Is (instance, expr, expr.Location).Resolve (rc);
2261 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2263 instance.Store (ec);
2265 base.EmitBranchable (ec, target, on_true);
2269 class PropertyPatternMember
2271 public PropertyPatternMember (string name, Expression expr, Location loc)
2278 public string Name { get; private set; }
2279 public Expression Expr { get; private set; }
2280 public Location Location { get; private set; }
2283 abstract class PatternExpression : Expression
2285 protected PatternExpression (Location loc)
2290 public override Expression CreateExpressionTree (ResolveContext ec)
2292 throw new NotImplementedException ();
2296 abstract class ComplexPatternExpression : PatternExpression
2298 protected Expression[] comparisons;
2300 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2303 TypeExpression = typeExpresion;
2306 public ATypeNameExpression TypeExpression { get; private set; }
2308 public override void Emit (EmitContext ec)
2310 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2313 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2315 if (comparisons != null) {
2316 foreach (var comp in comparisons) {
2317 comp.EmitBranchable (ec, target, false);
2324 /// Implementation of the `as' operator.
2326 public class As : Probe {
2328 public As (Expression expr, Expression probe_type, Location l)
2329 : base (expr, probe_type, l)
2333 protected override string OperatorName {
2334 get { return "as"; }
2337 public override Expression CreateExpressionTree (ResolveContext ec)
2339 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2340 expr.CreateExpressionTree (ec),
2341 new TypeOf (probe_type_expr, loc));
2343 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2346 public override void Emit (EmitContext ec)
2350 ec.Emit (OpCodes.Isinst, type);
2352 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2353 ec.Emit (OpCodes.Unbox_Any, type);
2356 protected override Expression DoResolve (ResolveContext ec)
2358 if (ResolveCommon (ec) == null)
2361 type = probe_type_expr;
2362 eclass = ExprClass.Value;
2363 TypeSpec etype = expr.Type;
2365 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2366 if (TypeManager.IsGenericParameter (type)) {
2367 ec.Report.Error (413, loc,
2368 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2369 probe_type_expr.GetSignatureForError ());
2371 ec.Report.Error (77, loc,
2372 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2373 type.GetSignatureForError ());
2378 if (expr.IsNull && type.IsNullableType) {
2379 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2382 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2383 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2387 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2389 e = EmptyCast.Create (e, type);
2390 return ReducedExpression.Create (e, this).Resolve (ec);
2393 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2394 if (TypeManager.IsGenericParameter (etype))
2395 expr = new BoxedCast (expr, etype);
2400 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2401 expr = new BoxedCast (expr, etype);
2405 if (etype != InternalType.ErrorType) {
2406 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2407 etype.GetSignatureForError (), type.GetSignatureForError ());
2413 public override object Accept (StructuralVisitor visitor)
2415 return visitor.Visit (this);
2420 // This represents a typecast in the source language.
2422 public class Cast : ShimExpression {
2423 Expression target_type;
2425 public Cast (Expression cast_type, Expression expr, Location loc)
2428 this.target_type = cast_type;
2432 public Expression TargetType {
2433 get { return target_type; }
2436 protected override Expression DoResolve (ResolveContext ec)
2438 expr = expr.Resolve (ec);
2442 type = target_type.ResolveAsType (ec);
2446 if (type.IsStatic) {
2447 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2451 if (type.IsPointer && !ec.IsUnsafe) {
2452 UnsafeError (ec, loc);
2455 eclass = ExprClass.Value;
2457 Constant c = expr as Constant;
2459 c = c.Reduce (ec, type);
2464 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2466 return EmptyCast.Create (res, type);
2471 protected override void CloneTo (CloneContext clonectx, Expression t)
2473 Cast target = (Cast) t;
2475 target.target_type = target_type.Clone (clonectx);
2476 target.expr = expr.Clone (clonectx);
2479 public override object Accept (StructuralVisitor visitor)
2481 return visitor.Visit (this);
2485 public class ImplicitCast : ShimExpression
2489 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2492 this.loc = expr.Location;
2494 this.arrayAccess = arrayAccess;
2497 protected override Expression DoResolve (ResolveContext ec)
2499 expr = expr.Resolve (ec);
2504 expr = ConvertExpressionToArrayIndex (ec, expr);
2506 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2512 public class DeclarationExpression : Expression, IMemoryLocation
2514 LocalVariableReference lvr;
2516 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2518 VariableType = variableType;
2519 Variable = variable;
2520 this.loc = variable.Location;
2523 public LocalVariable Variable { get; set; }
2524 public Expression Initializer { get; set; }
2525 public FullNamedExpression VariableType { get; set; }
2527 public void AddressOf (EmitContext ec, AddressOp mode)
2529 Variable.CreateBuilder (ec);
2531 if (Initializer != null) {
2532 lvr.EmitAssign (ec, Initializer, false, false);
2535 lvr.AddressOf (ec, mode);
2538 protected override void CloneTo (CloneContext clonectx, Expression t)
2540 var target = (DeclarationExpression) t;
2542 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2544 if (Initializer != null)
2545 target.Initializer = Initializer.Clone (clonectx);
2548 public override Expression CreateExpressionTree (ResolveContext rc)
2550 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2554 bool DoResolveCommon (ResolveContext rc)
2556 var var_expr = VariableType as VarExpr;
2557 if (var_expr != null) {
2558 type = InternalType.VarOutType;
2560 type = VariableType.ResolveAsType (rc);
2565 if (Initializer != null) {
2566 Initializer = Initializer.Resolve (rc);
2568 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2569 type = var_expr.Type;
2573 Variable.Type = type;
2574 lvr = new LocalVariableReference (Variable, loc);
2576 eclass = ExprClass.Variable;
2580 protected override Expression DoResolve (ResolveContext rc)
2582 if (DoResolveCommon (rc))
2588 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2590 if (lvr == null && DoResolveCommon (rc))
2591 lvr.ResolveLValue (rc, right_side);
2596 public override void Emit (EmitContext ec)
2598 throw new NotImplementedException ();
2603 // C# 2.0 Default value expression
2605 public class DefaultValueExpression : Expression
2609 public DefaultValueExpression (Expression expr, Location loc)
2615 public Expression Expr {
2621 public override bool IsSideEffectFree {
2627 public override bool ContainsEmitWithAwait ()
2632 public override Expression CreateExpressionTree (ResolveContext ec)
2634 Arguments args = new Arguments (2);
2635 args.Add (new Argument (this));
2636 args.Add (new Argument (new TypeOf (type, loc)));
2637 return CreateExpressionFactoryCall (ec, "Constant", args);
2640 protected override Expression DoResolve (ResolveContext ec)
2642 type = expr.ResolveAsType (ec);
2646 if (type.IsStatic) {
2647 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2651 return new NullLiteral (Location).ConvertImplicitly (type);
2653 if (TypeSpec.IsReferenceType (type))
2654 return new NullConstant (type, loc);
2656 Constant c = New.Constantify (type, expr.Location);
2660 eclass = ExprClass.Variable;
2664 public override void Emit (EmitContext ec)
2666 LocalTemporary temp_storage = new LocalTemporary(type);
2668 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2669 ec.Emit(OpCodes.Initobj, type);
2670 temp_storage.Emit(ec);
2671 temp_storage.Release (ec);
2675 public override SLE.Expression MakeExpression (BuilderContext ctx)
2677 return SLE.Expression.Default (type.GetMetaInfo ());
2681 protected override void CloneTo (CloneContext clonectx, Expression t)
2683 DefaultValueExpression target = (DefaultValueExpression) t;
2685 target.expr = expr.Clone (clonectx);
2688 public override object Accept (StructuralVisitor visitor)
2690 return visitor.Visit (this);
2695 /// Binary operators
2697 public class Binary : Expression, IDynamicBinder
2699 public class PredefinedOperator
2701 protected readonly TypeSpec left;
2702 protected readonly TypeSpec right;
2703 protected readonly TypeSpec left_unwrap;
2704 protected readonly TypeSpec right_unwrap;
2705 public readonly Operator OperatorsMask;
2706 public TypeSpec ReturnType;
2708 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2709 : this (ltype, rtype, op_mask, ltype)
2713 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2714 : this (type, type, op_mask, return_type)
2718 public PredefinedOperator (TypeSpec type, Operator op_mask)
2719 : this (type, type, op_mask, type)
2723 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2725 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2726 throw new InternalErrorException ("Only masked values can be used");
2728 if ((op_mask & Operator.NullableMask) != 0) {
2729 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2730 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2732 left_unwrap = ltype;
2733 right_unwrap = rtype;
2738 this.OperatorsMask = op_mask;
2739 this.ReturnType = return_type;
2742 public bool IsLifted {
2744 return (OperatorsMask & Operator.NullableMask) != 0;
2748 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2752 var left_expr = b.left;
2753 var right_expr = b.right;
2755 b.type = ReturnType;
2758 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2759 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2760 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2763 if (right_expr.IsNull) {
2764 if ((b.oper & Operator.EqualityMask) != 0) {
2765 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2766 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2767 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2768 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2769 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2771 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2772 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2774 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2775 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2777 return b.CreateLiftedValueTypeResult (rc, left);
2779 } else if (left_expr.IsNull) {
2780 if ((b.oper & Operator.EqualityMask) != 0) {
2781 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2782 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2783 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2784 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2785 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2787 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2788 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2790 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2791 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2793 return b.CreateLiftedValueTypeResult (rc, right);
2799 // A user operators does not support multiple user conversions, but decimal type
2800 // is considered to be predefined type therefore we apply predefined operators rules
2801 // and then look for decimal user-operator implementation
2803 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2804 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2805 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2807 return b.ResolveUserOperator (rc, b.left, b.right);
2810 c = right_expr as Constant;
2812 if (c.IsDefaultValue) {
2816 // (expr + 0) to expr
2817 // (expr - 0) to expr
2818 // (bool? | false) to bool?
2820 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2821 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2822 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2823 return ReducedExpression.Create (b.left, b).Resolve (rc);
2827 // Optimizes (value &/&& 0) to 0
2829 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2830 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2831 return ReducedExpression.Create (side_effect, b);
2835 // Optimizes (bool? & true) to bool?
2837 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2838 return ReducedExpression.Create (b.left, b).Resolve (rc);
2842 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2843 return ReducedExpression.Create (b.left, b).Resolve (rc);
2845 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2846 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2850 c = b.left as Constant;
2852 if (c.IsDefaultValue) {
2856 // (0 + expr) to expr
2857 // (false | bool?) to bool?
2859 if (b.oper == Operator.Addition ||
2860 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2861 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2862 return ReducedExpression.Create (b.right, b).Resolve (rc);
2866 // Optimizes (false && expr) to false
2868 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2869 // No rhs side-effects
2870 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2871 return ReducedExpression.Create (c, b);
2875 // Optimizes (0 & value) to 0
2877 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2878 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2879 return ReducedExpression.Create (side_effect, b);
2883 // Optimizes (true & bool?) to bool?
2885 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2886 return ReducedExpression.Create (b.right, b).Resolve (rc);
2890 // Optimizes (true || expr) to true
2892 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2893 // No rhs side-effects
2894 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2895 return ReducedExpression.Create (c, b);
2899 if (b.oper == Operator.Multiply && c.IsOneInteger)
2900 return ReducedExpression.Create (b.right, b).Resolve (rc);
2904 var lifted = new Nullable.LiftedBinaryOperator (b);
2906 TypeSpec ltype, rtype;
2907 if (b.left.Type.IsNullableType) {
2908 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2909 ltype = left_unwrap;
2914 if (b.right.Type.IsNullableType) {
2915 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2916 rtype = right_unwrap;
2921 lifted.Left = b.left.IsNull ?
2922 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2923 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2925 lifted.Right = b.right.IsNull ?
2926 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2927 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2929 return lifted.Resolve (rc);
2932 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2933 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2938 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2941 // We are dealing with primitive types only
2943 return left == ltype && ltype == rtype;
2946 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2949 if (left == lexpr.Type && right == rexpr.Type)
2952 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2953 Convert.ImplicitConversionExists (ec, rexpr, right);
2956 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2958 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2959 return best_operator;
2961 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2965 if (left != null && best_operator.left != null) {
2966 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2970 // When second argument is same as the first one, the result is same
2972 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2973 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2976 if (result == 0 || result > 2)
2979 return result == 1 ? best_operator : this;
2983 sealed class PredefinedStringOperator : PredefinedOperator
2985 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2986 : base (type, type, op_mask, retType)
2990 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2991 : base (ltype, rtype, op_mask, retType)
2995 public override Expression ConvertResult (ResolveContext ec, Binary b)
2998 // Use original expression for nullable arguments
3000 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3002 b.left = unwrap.Original;
3004 unwrap = b.right as Nullable.Unwrap;
3006 b.right = unwrap.Original;
3008 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3009 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3012 // Start a new concat expression using converted expression
3014 return StringConcat.Create (ec, b.left, b.right, b.loc);
3018 sealed class PredefinedEqualityOperator : PredefinedOperator
3020 MethodSpec equal_method, inequal_method;
3022 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3023 : base (arg, arg, Operator.EqualityMask, retType)
3027 public override Expression ConvertResult (ResolveContext ec, Binary b)
3029 b.type = ReturnType;
3031 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3032 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3034 Arguments args = new Arguments (2);
3035 args.Add (new Argument (b.left));
3036 args.Add (new Argument (b.right));
3039 if (b.oper == Operator.Equality) {
3040 if (equal_method == null) {
3041 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3042 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3043 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3044 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3046 throw new NotImplementedException (left.GetSignatureForError ());
3049 method = equal_method;
3051 if (inequal_method == null) {
3052 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3053 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3054 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3055 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3057 throw new NotImplementedException (left.GetSignatureForError ());
3060 method = inequal_method;
3063 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3067 class PredefinedPointerOperator : PredefinedOperator
3069 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3070 : base (ltype, rtype, op_mask)
3074 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3075 : base (ltype, rtype, op_mask, retType)
3079 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3080 : base (type, op_mask, return_type)
3084 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3087 if (!lexpr.Type.IsPointer)
3090 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3094 if (right == null) {
3095 if (!rexpr.Type.IsPointer)
3098 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3105 public override Expression ConvertResult (ResolveContext ec, Binary b)
3108 b.left = EmptyCast.Create (b.left, left);
3109 } else if (right != null) {
3110 b.right = EmptyCast.Create (b.right, right);
3113 TypeSpec r_type = ReturnType;
3114 Expression left_arg, right_arg;
3115 if (r_type == null) {
3118 right_arg = b.right;
3119 r_type = b.left.Type;
3123 r_type = b.right.Type;
3127 right_arg = b.right;
3130 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3135 public enum Operator {
3136 Multiply = 0 | ArithmeticMask,
3137 Division = 1 | ArithmeticMask,
3138 Modulus = 2 | ArithmeticMask,
3139 Addition = 3 | ArithmeticMask | AdditionMask,
3140 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3142 LeftShift = 5 | ShiftMask,
3143 RightShift = 6 | ShiftMask,
3145 LessThan = 7 | ComparisonMask | RelationalMask,
3146 GreaterThan = 8 | ComparisonMask | RelationalMask,
3147 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3148 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3149 Equality = 11 | ComparisonMask | EqualityMask,
3150 Inequality = 12 | ComparisonMask | EqualityMask,
3152 BitwiseAnd = 13 | BitwiseMask,
3153 ExclusiveOr = 14 | BitwiseMask,
3154 BitwiseOr = 15 | BitwiseMask,
3156 LogicalAnd = 16 | LogicalMask,
3157 LogicalOr = 17 | LogicalMask,
3162 ValuesOnlyMask = ArithmeticMask - 1,
3163 ArithmeticMask = 1 << 5,
3165 ComparisonMask = 1 << 7,
3166 EqualityMask = 1 << 8,
3167 BitwiseMask = 1 << 9,
3168 LogicalMask = 1 << 10,
3169 AdditionMask = 1 << 11,
3170 SubtractionMask = 1 << 12,
3171 RelationalMask = 1 << 13,
3173 DecomposedMask = 1 << 19,
3174 NullableMask = 1 << 20
3178 public enum State : byte
3182 UserOperatorsExcluded = 1 << 2
3185 readonly Operator oper;
3186 Expression left, right;
3188 ConvCast.Mode enum_conversion;
3190 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3191 : this (oper, left, right, State.Compound)
3195 public Binary (Operator oper, Expression left, Expression right, State state)
3196 : this (oper, left, right)
3201 public Binary (Operator oper, Expression left, Expression right)
3202 : this (oper, left, right, left.Location)
3206 public Binary (Operator oper, Expression left, Expression right, Location loc)
3216 public bool IsCompound {
3218 return (state & State.Compound) != 0;
3222 public Operator Oper {
3228 public Expression Left {
3234 public Expression Right {
3240 public override Location StartLocation {
3242 return left.StartLocation;
3249 /// Returns a stringified representation of the Operator
3251 string OperName (Operator oper)
3255 case Operator.Multiply:
3258 case Operator.Division:
3261 case Operator.Modulus:
3264 case Operator.Addition:
3267 case Operator.Subtraction:
3270 case Operator.LeftShift:
3273 case Operator.RightShift:
3276 case Operator.LessThan:
3279 case Operator.GreaterThan:
3282 case Operator.LessThanOrEqual:
3285 case Operator.GreaterThanOrEqual:
3288 case Operator.Equality:
3291 case Operator.Inequality:
3294 case Operator.BitwiseAnd:
3297 case Operator.BitwiseOr:
3300 case Operator.ExclusiveOr:
3303 case Operator.LogicalOr:
3306 case Operator.LogicalAnd:
3310 s = oper.ToString ();
3320 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3322 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3325 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3327 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3331 l = left.Type.GetSignatureForError ();
3332 r = right.Type.GetSignatureForError ();
3334 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3338 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3340 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3343 public override void FlowAnalysis (FlowAnalysisContext fc)
3346 // Optimized version when on-true/on-false data are not needed
3348 if ((oper & Operator.LogicalMask) == 0) {
3349 left.FlowAnalysis (fc);
3350 right.FlowAnalysis (fc);
3354 left.FlowAnalysisConditional (fc);
3355 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3356 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3358 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3359 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3360 right.FlowAnalysisConditional (fc);
3362 if (oper == Operator.LogicalOr)
3363 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3365 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3368 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3370 if ((oper & Operator.LogicalMask) == 0) {
3371 base.FlowAnalysisConditional (fc);
3375 left.FlowAnalysisConditional (fc);
3376 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3377 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3379 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3380 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3381 right.FlowAnalysisConditional (fc);
3383 var lc = left as Constant;
3384 if (oper == Operator.LogicalOr) {
3385 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3386 if (lc != null && lc.IsDefaultValue)
3387 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3389 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3391 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3392 if (lc != null && !lc.IsDefaultValue)
3393 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3395 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3400 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3402 string GetOperatorExpressionTypeName ()
3405 case Operator.Addition:
3406 return IsCompound ? "AddAssign" : "Add";
3407 case Operator.BitwiseAnd:
3408 return IsCompound ? "AndAssign" : "And";
3409 case Operator.BitwiseOr:
3410 return IsCompound ? "OrAssign" : "Or";
3411 case Operator.Division:
3412 return IsCompound ? "DivideAssign" : "Divide";
3413 case Operator.ExclusiveOr:
3414 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3415 case Operator.Equality:
3417 case Operator.GreaterThan:
3418 return "GreaterThan";
3419 case Operator.GreaterThanOrEqual:
3420 return "GreaterThanOrEqual";
3421 case Operator.Inequality:
3423 case Operator.LeftShift:
3424 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3425 case Operator.LessThan:
3427 case Operator.LessThanOrEqual:
3428 return "LessThanOrEqual";
3429 case Operator.LogicalAnd:
3431 case Operator.LogicalOr:
3433 case Operator.Modulus:
3434 return IsCompound ? "ModuloAssign" : "Modulo";
3435 case Operator.Multiply:
3436 return IsCompound ? "MultiplyAssign" : "Multiply";
3437 case Operator.RightShift:
3438 return IsCompound ? "RightShiftAssign" : "RightShift";
3439 case Operator.Subtraction:
3440 return IsCompound ? "SubtractAssign" : "Subtract";
3442 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3446 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3449 case Operator.Addition:
3450 return CSharp.Operator.OpType.Addition;
3451 case Operator.BitwiseAnd:
3452 case Operator.LogicalAnd:
3453 return CSharp.Operator.OpType.BitwiseAnd;
3454 case Operator.BitwiseOr:
3455 case Operator.LogicalOr:
3456 return CSharp.Operator.OpType.BitwiseOr;
3457 case Operator.Division:
3458 return CSharp.Operator.OpType.Division;
3459 case Operator.Equality:
3460 return CSharp.Operator.OpType.Equality;
3461 case Operator.ExclusiveOr:
3462 return CSharp.Operator.OpType.ExclusiveOr;
3463 case Operator.GreaterThan:
3464 return CSharp.Operator.OpType.GreaterThan;
3465 case Operator.GreaterThanOrEqual:
3466 return CSharp.Operator.OpType.GreaterThanOrEqual;
3467 case Operator.Inequality:
3468 return CSharp.Operator.OpType.Inequality;
3469 case Operator.LeftShift:
3470 return CSharp.Operator.OpType.LeftShift;
3471 case Operator.LessThan:
3472 return CSharp.Operator.OpType.LessThan;
3473 case Operator.LessThanOrEqual:
3474 return CSharp.Operator.OpType.LessThanOrEqual;
3475 case Operator.Modulus:
3476 return CSharp.Operator.OpType.Modulus;
3477 case Operator.Multiply:
3478 return CSharp.Operator.OpType.Multiply;
3479 case Operator.RightShift:
3480 return CSharp.Operator.OpType.RightShift;
3481 case Operator.Subtraction:
3482 return CSharp.Operator.OpType.Subtraction;
3484 throw new InternalErrorException (op.ToString ());
3488 public override bool ContainsEmitWithAwait ()
3490 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3493 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3498 case Operator.Multiply:
3499 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3500 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3501 opcode = OpCodes.Mul_Ovf;
3502 else if (!IsFloat (l))
3503 opcode = OpCodes.Mul_Ovf_Un;
3505 opcode = OpCodes.Mul;
3507 opcode = OpCodes.Mul;
3511 case Operator.Division:
3513 opcode = OpCodes.Div_Un;
3515 opcode = OpCodes.Div;
3518 case Operator.Modulus:
3520 opcode = OpCodes.Rem_Un;
3522 opcode = OpCodes.Rem;
3525 case Operator.Addition:
3526 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3527 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3528 opcode = OpCodes.Add_Ovf;
3529 else if (!IsFloat (l))
3530 opcode = OpCodes.Add_Ovf_Un;
3532 opcode = OpCodes.Add;
3534 opcode = OpCodes.Add;
3537 case Operator.Subtraction:
3538 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3539 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3540 opcode = OpCodes.Sub_Ovf;
3541 else if (!IsFloat (l))
3542 opcode = OpCodes.Sub_Ovf_Un;
3544 opcode = OpCodes.Sub;
3546 opcode = OpCodes.Sub;
3549 case Operator.RightShift:
3550 if (!(right is IntConstant)) {
3551 ec.EmitInt (GetShiftMask (l));
3552 ec.Emit (OpCodes.And);
3556 opcode = OpCodes.Shr_Un;
3558 opcode = OpCodes.Shr;
3561 case Operator.LeftShift:
3562 if (!(right is IntConstant)) {
3563 ec.EmitInt (GetShiftMask (l));
3564 ec.Emit (OpCodes.And);
3567 opcode = OpCodes.Shl;
3570 case Operator.Equality:
3571 opcode = OpCodes.Ceq;
3574 case Operator.Inequality:
3575 ec.Emit (OpCodes.Ceq);
3578 opcode = OpCodes.Ceq;
3581 case Operator.LessThan:
3583 opcode = OpCodes.Clt_Un;
3585 opcode = OpCodes.Clt;
3588 case Operator.GreaterThan:
3590 opcode = OpCodes.Cgt_Un;
3592 opcode = OpCodes.Cgt;
3595 case Operator.LessThanOrEqual:
3596 if (IsUnsigned (l) || IsFloat (l))
3597 ec.Emit (OpCodes.Cgt_Un);
3599 ec.Emit (OpCodes.Cgt);
3602 opcode = OpCodes.Ceq;
3605 case Operator.GreaterThanOrEqual:
3606 if (IsUnsigned (l) || IsFloat (l))
3607 ec.Emit (OpCodes.Clt_Un);
3609 ec.Emit (OpCodes.Clt);
3613 opcode = OpCodes.Ceq;
3616 case Operator.BitwiseOr:
3617 opcode = OpCodes.Or;
3620 case Operator.BitwiseAnd:
3621 opcode = OpCodes.And;
3624 case Operator.ExclusiveOr:
3625 opcode = OpCodes.Xor;
3629 throw new InternalErrorException (oper.ToString ());
3635 static int GetShiftMask (TypeSpec type)
3637 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3640 static bool IsUnsigned (TypeSpec t)
3642 switch (t.BuiltinType) {
3643 case BuiltinTypeSpec.Type.Char:
3644 case BuiltinTypeSpec.Type.UInt:
3645 case BuiltinTypeSpec.Type.ULong:
3646 case BuiltinTypeSpec.Type.UShort:
3647 case BuiltinTypeSpec.Type.Byte:
3654 static bool IsFloat (TypeSpec t)
3656 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3659 public Expression ResolveOperator (ResolveContext rc)
3661 eclass = ExprClass.Value;
3663 TypeSpec l = left.Type;
3664 TypeSpec r = right.Type;
3666 bool primitives_only = false;
3669 // Handles predefined primitive types
3671 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3672 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3673 if ((oper & Operator.ShiftMask) == 0) {
3674 if (!DoBinaryOperatorPromotion (rc))
3677 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3681 if (l.IsPointer || r.IsPointer)
3682 return ResolveOperatorPointer (rc, l, r);
3685 if ((state & State.UserOperatorsExcluded) == 0) {
3686 expr = ResolveUserOperator (rc, left, right);
3691 bool lenum = l.IsEnum;
3692 bool renum = r.IsEnum;
3693 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3697 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3698 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3703 if ((oper & Operator.BitwiseMask) != 0) {
3704 expr = EmptyCast.Create (expr, type);
3705 enum_conversion = GetEnumResultCast (type);
3707 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3708 expr = OptimizeAndOperation (expr);
3712 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3713 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3716 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3717 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3721 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3724 // We cannot break here there is also Enum + String possible match
3725 // which is not ambiguous with predefined enum operators
3728 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3729 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3733 } else if (l.IsDelegate || r.IsDelegate) {
3737 expr = ResolveOperatorDelegate (rc, l, r);
3739 // TODO: Can this be ambiguous
3747 // Equality operators are more complicated
3749 if ((oper & Operator.EqualityMask) != 0) {
3750 return ResolveEquality (rc, l, r, primitives_only);
3753 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3757 if (primitives_only)
3761 // Lifted operators have lower priority
3763 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3766 static bool IsEnumOrNullableEnum (TypeSpec type)
3768 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3772 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3773 // if 'left' is not an enumeration constant, create one from the type of 'right'
3774 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3777 case Operator.BitwiseOr:
3778 case Operator.BitwiseAnd:
3779 case Operator.ExclusiveOr:
3780 case Operator.Equality:
3781 case Operator.Inequality:
3782 case Operator.LessThan:
3783 case Operator.LessThanOrEqual:
3784 case Operator.GreaterThan:
3785 case Operator.GreaterThanOrEqual:
3786 if (left.Type.IsEnum)
3789 if (left.IsZeroInteger)
3790 return left.Reduce (ec, right.Type);
3794 case Operator.Addition:
3795 case Operator.Subtraction:
3798 case Operator.Multiply:
3799 case Operator.Division:
3800 case Operator.Modulus:
3801 case Operator.LeftShift:
3802 case Operator.RightShift:
3803 if (right.Type.IsEnum || left.Type.IsEnum)
3812 // The `|' operator used on types which were extended is dangerous
3814 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3816 OpcodeCast lcast = left as OpcodeCast;
3817 if (lcast != null) {
3818 if (IsUnsigned (lcast.UnderlyingType))
3822 OpcodeCast rcast = right as OpcodeCast;
3823 if (rcast != null) {
3824 if (IsUnsigned (rcast.UnderlyingType))
3828 if (lcast == null && rcast == null)
3831 // FIXME: consider constants
3833 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3834 ec.Report.Warning (675, 3, loc,
3835 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3836 ltype.GetSignatureForError ());
3839 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3841 return new PredefinedOperator[] {
3843 // Pointer arithmetic:
3845 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3846 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3847 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3848 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3850 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3851 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3852 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3853 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3856 // T* operator + (int y, T* x);
3857 // T* operator + (uint y, T *x);
3858 // T* operator + (long y, T *x);
3859 // T* operator + (ulong y, T *x);
3861 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3862 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3863 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3864 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3867 // long operator - (T* x, T *y)
3869 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3873 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3875 TypeSpec bool_type = types.Bool;
3878 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3879 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3880 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3881 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3882 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3883 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3884 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3886 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3887 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3888 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3889 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3890 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3891 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3892 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3894 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3895 // Remaining string operators are in lifted tables
3897 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3899 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3900 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3901 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3905 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3907 var types = module.Compiler.BuiltinTypes;
3910 // Not strictly lifted but need to be in second group otherwise expressions like
3911 // int + null would resolve to +(object, string) instead of +(int?, int?)
3913 var string_operators = new [] {
3914 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3915 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3918 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3919 if (nullable == null)
3920 return string_operators;
3922 var bool_type = types.Bool;
3924 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3925 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3926 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3927 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3928 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3929 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3930 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3931 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3934 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3935 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3936 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3937 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3938 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3939 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3940 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3942 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3943 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3944 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3945 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3946 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3947 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3948 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3950 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3952 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3953 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3954 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3956 string_operators [0],
3957 string_operators [1]
3961 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3963 TypeSpec bool_type = types.Bool;
3966 new PredefinedEqualityOperator (types.String, bool_type),
3967 new PredefinedEqualityOperator (types.Delegate, bool_type),
3968 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3969 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3970 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3971 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3972 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3973 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3975 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3979 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3981 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3983 if (nullable == null)
3984 return new PredefinedOperator [0];
3986 var types = module.Compiler.BuiltinTypes;
3987 var bool_type = types.Bool;
3988 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3989 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3990 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3991 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3992 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3993 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3994 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3995 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3998 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3999 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4000 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4001 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4002 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4003 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4005 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4010 // 7.2.6.2 Binary numeric promotions
4012 bool DoBinaryOperatorPromotion (ResolveContext rc)
4014 TypeSpec ltype = left.Type;
4015 if (ltype.IsNullableType) {
4016 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4020 // This is numeric promotion code only
4022 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4025 TypeSpec rtype = right.Type;
4026 if (rtype.IsNullableType) {
4027 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4030 var lb = ltype.BuiltinType;
4031 var rb = rtype.BuiltinType;
4035 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4036 type = rc.BuiltinTypes.Decimal;
4037 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4038 type = rc.BuiltinTypes.Double;
4039 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4040 type = rc.BuiltinTypes.Float;
4041 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4042 type = rc.BuiltinTypes.ULong;
4044 if (IsSignedType (lb)) {
4045 expr = ConvertSignedConstant (left, type);
4049 } else if (IsSignedType (rb)) {
4050 expr = ConvertSignedConstant (right, type);
4056 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4057 type = rc.BuiltinTypes.Long;
4058 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4059 type = rc.BuiltinTypes.UInt;
4061 if (IsSignedType (lb)) {
4062 expr = ConvertSignedConstant (left, type);
4064 type = rc.BuiltinTypes.Long;
4065 } else if (IsSignedType (rb)) {
4066 expr = ConvertSignedConstant (right, type);
4068 type = rc.BuiltinTypes.Long;
4071 type = rc.BuiltinTypes.Int;
4074 if (ltype != type) {
4075 expr = PromoteExpression (rc, left, type);
4082 if (rtype != type) {
4083 expr = PromoteExpression (rc, right, type);
4093 static bool IsSignedType (BuiltinTypeSpec.Type type)
4096 case BuiltinTypeSpec.Type.Int:
4097 case BuiltinTypeSpec.Type.Short:
4098 case BuiltinTypeSpec.Type.SByte:
4099 case BuiltinTypeSpec.Type.Long:
4106 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4108 var c = expr as Constant;
4112 return c.ConvertImplicitly (type);
4115 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4117 if (expr.Type.IsNullableType) {
4118 return Convert.ImplicitConversionStandard (rc, expr,
4119 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4122 var c = expr as Constant;
4124 return c.ConvertImplicitly (type);
4126 return Convert.ImplicitNumericConversion (expr, type);
4129 protected override Expression DoResolve (ResolveContext ec)
4134 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4135 left = ((ParenthesizedExpression) left).Expr;
4136 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4140 if (left.eclass == ExprClass.Type) {
4141 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4145 left = left.Resolve (ec);
4150 right = right.Resolve (ec);
4154 Constant lc = left as Constant;
4155 Constant rc = right as Constant;
4157 // The conversion rules are ignored in enum context but why
4158 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4159 lc = EnumLiftUp (ec, lc, rc);
4161 rc = EnumLiftUp (ec, rc, lc);
4164 if (rc != null && lc != null) {
4165 int prev_e = ec.Report.Errors;
4166 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4167 if (e != null || ec.Report.Errors != prev_e)
4171 // Comparison warnings
4172 if ((oper & Operator.ComparisonMask) != 0) {
4173 if (left.Equals (right)) {
4174 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4176 CheckOutOfRangeComparison (ec, lc, right.Type);
4177 CheckOutOfRangeComparison (ec, rc, left.Type);
4180 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4181 return DoResolveDynamic (ec);
4183 return DoResolveCore (ec, left, right);
4186 Expression DoResolveDynamic (ResolveContext rc)
4189 var rt = right.Type;
4190 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4191 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4192 Error_OperatorCannotBeApplied (rc, left, right);
4199 // Special handling for logical boolean operators which require rhs not to be
4200 // evaluated based on lhs value
4202 if ((oper & Operator.LogicalMask) != 0) {
4203 Expression cond_left, cond_right, expr;
4205 args = new Arguments (2);
4207 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4208 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4210 var cond_args = new Arguments (1);
4211 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4214 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4215 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4217 left = temp.CreateReferenceExpression (rc, loc);
4218 if (oper == Operator.LogicalAnd) {
4219 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4222 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4226 args.Add (new Argument (left));
4227 args.Add (new Argument (right));
4228 cond_right = new DynamicExpressionStatement (this, args, loc);
4230 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4232 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4233 rc.Report.Error (7083, left.Location,
4234 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4235 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4239 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4240 args.Add (new Argument (right));
4241 right = new DynamicExpressionStatement (this, args, loc);
4244 // bool && dynamic => (temp = left) ? temp && right : temp;
4245 // bool || dynamic => (temp = left) ? temp : temp || right;
4247 if (oper == Operator.LogicalAnd) {
4249 cond_right = temp.CreateReferenceExpression (rc, loc);
4251 cond_left = temp.CreateReferenceExpression (rc, loc);
4255 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4258 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4261 args = new Arguments (2);
4262 args.Add (new Argument (left));
4263 args.Add (new Argument (right));
4264 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4267 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4269 Expression expr = ResolveOperator (ec);
4271 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4273 if (left == null || right == null)
4274 throw new InternalErrorException ("Invalid conversion");
4276 if (oper == Operator.BitwiseOr)
4277 CheckBitwiseOrOnSignExtended (ec);
4282 public override SLE.Expression MakeExpression (BuilderContext ctx)
4284 return MakeExpression (ctx, left, right);
4287 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4289 var le = left.MakeExpression (ctx);
4290 var re = right.MakeExpression (ctx);
4291 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4294 case Operator.Addition:
4295 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4296 case Operator.BitwiseAnd:
4297 return SLE.Expression.And (le, re);
4298 case Operator.BitwiseOr:
4299 return SLE.Expression.Or (le, re);
4300 case Operator.Division:
4301 return SLE.Expression.Divide (le, re);
4302 case Operator.Equality:
4303 return SLE.Expression.Equal (le, re);
4304 case Operator.ExclusiveOr:
4305 return SLE.Expression.ExclusiveOr (le, re);
4306 case Operator.GreaterThan:
4307 return SLE.Expression.GreaterThan (le, re);
4308 case Operator.GreaterThanOrEqual:
4309 return SLE.Expression.GreaterThanOrEqual (le, re);
4310 case Operator.Inequality:
4311 return SLE.Expression.NotEqual (le, re);
4312 case Operator.LeftShift:
4313 return SLE.Expression.LeftShift (le, re);
4314 case Operator.LessThan:
4315 return SLE.Expression.LessThan (le, re);
4316 case Operator.LessThanOrEqual:
4317 return SLE.Expression.LessThanOrEqual (le, re);
4318 case Operator.LogicalAnd:
4319 return SLE.Expression.AndAlso (le, re);
4320 case Operator.LogicalOr:
4321 return SLE.Expression.OrElse (le, re);
4322 case Operator.Modulus:
4323 return SLE.Expression.Modulo (le, re);
4324 case Operator.Multiply:
4325 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4326 case Operator.RightShift:
4327 return SLE.Expression.RightShift (le, re);
4328 case Operator.Subtraction:
4329 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4331 throw new NotImplementedException (oper.ToString ());
4336 // D operator + (D x, D y)
4337 // D operator - (D x, D y)
4339 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4341 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4343 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4344 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4349 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4350 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4360 MethodSpec method = null;
4361 Arguments args = new Arguments (2);
4362 args.Add (new Argument (left));
4363 args.Add (new Argument (right));
4365 if (oper == Operator.Addition) {
4366 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4367 } else if (oper == Operator.Subtraction) {
4368 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4372 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4374 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4375 return new ClassCast (expr, l);
4379 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4381 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4384 // bool operator == (E x, E y);
4385 // bool operator != (E x, E y);
4386 // bool operator < (E x, E y);
4387 // bool operator > (E x, E y);
4388 // bool operator <= (E x, E y);
4389 // bool operator >= (E x, E y);
4391 // E operator & (E x, E y);
4392 // E operator | (E x, E y);
4393 // E operator ^ (E x, E y);
4396 if ((oper & Operator.ComparisonMask) != 0) {
4397 type = rc.BuiltinTypes.Bool;
4403 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4409 if (ltype == rtype) {
4413 var lifted = new Nullable.LiftedBinaryOperator (this);
4415 lifted.Right = right;
4416 return lifted.Resolve (rc);
4419 if (renum && !ltype.IsNullableType) {
4420 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4425 } else if (lenum && !rtype.IsNullableType) {
4426 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4434 // Now try lifted version of predefined operator
4436 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4437 if (nullable_type != null) {
4438 if (renum && !ltype.IsNullableType) {
4439 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4441 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4444 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4447 if ((oper & Operator.BitwiseMask) != 0)
4451 if ((oper & Operator.BitwiseMask) != 0)
4452 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4454 return CreateLiftedValueTypeResult (rc, rtype);
4458 var lifted = new Nullable.LiftedBinaryOperator (this);
4460 lifted.Right = right;
4461 return lifted.Resolve (rc);
4463 } else if (lenum && !rtype.IsNullableType) {
4464 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4466 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4469 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4472 if ((oper & Operator.BitwiseMask) != 0)
4476 if ((oper & Operator.BitwiseMask) != 0)
4477 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4479 return CreateLiftedValueTypeResult (rc, ltype);
4483 var lifted = new Nullable.LiftedBinaryOperator (this);
4485 lifted.Right = expr;
4486 return lifted.Resolve (rc);
4488 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4489 Nullable.Unwrap unwrap = null;
4490 if (left.IsNull || right.IsNull) {
4491 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4492 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4494 if ((oper & Operator.RelationalMask) != 0)
4495 return CreateLiftedValueTypeResult (rc, rtype);
4497 if ((oper & Operator.BitwiseMask) != 0)
4498 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4501 return CreateLiftedValueTypeResult (rc, left.Type);
4503 // Equality operators are valid between E? and null
4505 unwrap = new Nullable.Unwrap (right);
4507 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4511 if ((oper & Operator.BitwiseMask) != 0)
4516 var lifted = new Nullable.LiftedBinaryOperator (this);
4518 lifted.Right = right;
4519 lifted.UnwrapRight = unwrap;
4520 return lifted.Resolve (rc);
4522 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4523 Nullable.Unwrap unwrap = null;
4524 if (right.IsNull || left.IsNull) {
4525 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4526 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4528 if ((oper & Operator.RelationalMask) != 0)
4529 return CreateLiftedValueTypeResult (rc, ltype);
4531 if ((oper & Operator.BitwiseMask) != 0)
4532 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4535 return CreateLiftedValueTypeResult (rc, right.Type);
4537 // Equality operators are valid between E? and null
4539 unwrap = new Nullable.Unwrap (left);
4541 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4545 if ((oper & Operator.BitwiseMask) != 0)
4550 var lifted = new Nullable.LiftedBinaryOperator (this);
4552 lifted.UnwrapLeft = unwrap;
4553 lifted.Right = expr;
4554 return lifted.Resolve (rc);
4562 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4564 TypeSpec underlying_type;
4565 if (expr.Type.IsNullableType) {
4566 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4568 underlying_type = EnumSpec.GetUnderlyingType (nt);
4570 underlying_type = nt;
4571 } else if (expr.Type.IsEnum) {
4572 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4574 underlying_type = expr.Type;
4577 switch (underlying_type.BuiltinType) {
4578 case BuiltinTypeSpec.Type.SByte:
4579 case BuiltinTypeSpec.Type.Byte:
4580 case BuiltinTypeSpec.Type.Short:
4581 case BuiltinTypeSpec.Type.UShort:
4582 underlying_type = rc.BuiltinTypes.Int;
4586 if (expr.Type.IsNullableType || liftType)
4587 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4589 if (expr.Type == underlying_type)
4592 return EmptyCast.Create (expr, underlying_type);
4595 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4598 // U operator - (E e, E f)
4599 // E operator - (E e, U x) // Internal decomposition operator
4600 // E operator - (U x, E e) // Internal decomposition operator
4602 // E operator + (E e, U x)
4603 // E operator + (U x, E e)
4612 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4618 if (!enum_type.IsNullableType) {
4619 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4621 if (oper == Operator.Subtraction)
4622 expr = ConvertEnumSubtractionResult (rc, expr);
4624 expr = ConvertEnumAdditionalResult (expr, enum_type);
4626 enum_conversion = GetEnumResultCast (expr.Type);
4631 var nullable = rc.Module.PredefinedTypes.Nullable;
4634 // Don't try nullable version when nullable type is undefined
4636 if (!nullable.IsDefined)
4639 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4642 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4644 if (oper == Operator.Subtraction)
4645 expr = ConvertEnumSubtractionResult (rc, expr);
4647 expr = ConvertEnumAdditionalResult (expr, enum_type);
4649 enum_conversion = GetEnumResultCast (expr.Type);
4655 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4657 return EmptyCast.Create (expr, enumType);
4660 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4663 // Enumeration subtraction has different result type based on
4666 TypeSpec result_type;
4667 if (left.Type == right.Type) {
4668 var c = right as EnumConstant;
4669 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4671 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4672 // E which is not what expressions E - 1 or 0 - E return
4674 result_type = left.Type;
4676 result_type = left.Type.IsNullableType ?
4677 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4678 EnumSpec.GetUnderlyingType (left.Type);
4681 if (IsEnumOrNullableEnum (left.Type)) {
4682 result_type = left.Type;
4684 result_type = right.Type;
4687 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4688 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4691 return EmptyCast.Create (expr, result_type);
4694 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4696 if (type.IsNullableType)
4697 type = Nullable.NullableInfo.GetUnderlyingType (type);
4700 type = EnumSpec.GetUnderlyingType (type);
4702 switch (type.BuiltinType) {
4703 case BuiltinTypeSpec.Type.SByte:
4704 return ConvCast.Mode.I4_I1;
4705 case BuiltinTypeSpec.Type.Byte:
4706 return ConvCast.Mode.I4_U1;
4707 case BuiltinTypeSpec.Type.Short:
4708 return ConvCast.Mode.I4_I2;
4709 case BuiltinTypeSpec.Type.UShort:
4710 return ConvCast.Mode.I4_U2;
4717 // Equality operators rules
4719 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4722 type = ec.BuiltinTypes.Bool;
4723 bool no_arg_conv = false;
4725 if (!primitives_only) {
4728 // a, Both operands are reference-type values or the value null
4729 // b, One operand is a value of type T where T is a type-parameter and
4730 // the other operand is the value null. Furthermore T does not have the
4731 // value type constraint
4733 // LAMESPEC: Very confusing details in the specification, basically any
4734 // reference like type-parameter is allowed
4736 var tparam_l = l as TypeParameterSpec;
4737 var tparam_r = r as TypeParameterSpec;
4738 if (tparam_l != null) {
4739 if (right is NullLiteral) {
4740 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4743 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4747 if (!tparam_l.IsReferenceType)
4750 l = tparam_l.GetEffectiveBase ();
4751 left = new BoxedCast (left, l);
4752 } else if (left is NullLiteral && tparam_r == null) {
4753 if (TypeSpec.IsReferenceType (r))
4756 if (r.Kind == MemberKind.InternalCompilerType)
4760 if (tparam_r != null) {
4761 if (left is NullLiteral) {
4762 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4765 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4769 if (!tparam_r.IsReferenceType)
4772 r = tparam_r.GetEffectiveBase ();
4773 right = new BoxedCast (right, r);
4774 } else if (right is NullLiteral) {
4775 if (TypeSpec.IsReferenceType (l))
4778 if (l.Kind == MemberKind.InternalCompilerType)
4783 // LAMESPEC: method groups can be compared when they convert to other side delegate
4786 if (right.eclass == ExprClass.MethodGroup) {
4787 result = Convert.ImplicitConversion (ec, right, l, loc);
4793 } else if (r.IsDelegate && l != r) {
4796 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4797 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4804 no_arg_conv = l == r && !l.IsStruct;
4809 // bool operator != (string a, string b)
4810 // bool operator == (string a, string b)
4812 // bool operator != (Delegate a, Delegate b)
4813 // bool operator == (Delegate a, Delegate b)
4815 // bool operator != (bool a, bool b)
4816 // bool operator == (bool a, bool b)
4818 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4819 // they implement an implicit conversion to any of types above. This does
4820 // not apply when both operands are of same reference type
4822 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4823 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4828 // Now try lifted version of predefined operators
4830 if (no_arg_conv && !l.IsNullableType) {
4832 // Optimizes cases which won't match
4835 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4841 // The == and != operators permit one operand to be a value of a nullable
4842 // type and the other to be the null literal, even if no predefined or user-defined
4843 // operator (in unlifted or lifted form) exists for the operation.
4845 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4846 var lifted = new Nullable.LiftedBinaryOperator (this);
4848 lifted.Right = right;
4849 return lifted.Resolve (ec);
4854 // bool operator != (object a, object b)
4855 // bool operator == (object a, object b)
4857 // An explicit reference conversion exists from the
4858 // type of either operand to the type of the other operand.
4861 // Optimize common path
4863 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4866 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4867 !Convert.ExplicitReferenceConversionExists (r, l))
4870 // Reject allowed explicit conversions like int->object
4871 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4874 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4875 ec.Report.Warning (253, 2, loc,
4876 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4877 l.GetSignatureForError ());
4879 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4880 ec.Report.Warning (252, 2, loc,
4881 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4882 r.GetSignatureForError ());
4888 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4891 // bool operator == (void* x, void* y);
4892 // bool operator != (void* x, void* y);
4893 // bool operator < (void* x, void* y);
4894 // bool operator > (void* x, void* y);
4895 // bool operator <= (void* x, void* y);
4896 // bool operator >= (void* x, void* y);
4898 if ((oper & Operator.ComparisonMask) != 0) {
4901 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4908 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4914 type = ec.BuiltinTypes.Bool;
4918 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4922 // Build-in operators method overloading
4924 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4926 PredefinedOperator best_operator = null;
4927 TypeSpec l = left.Type;
4928 TypeSpec r = right.Type;
4929 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4931 foreach (PredefinedOperator po in operators) {
4932 if ((po.OperatorsMask & oper_mask) == 0)
4935 if (primitives_only) {
4936 if (!po.IsPrimitiveApplicable (l, r))
4939 if (!po.IsApplicable (ec, left, right))
4943 if (best_operator == null) {
4945 if (primitives_only)
4951 best_operator = po.ResolveBetterOperator (ec, best_operator);
4953 if (best_operator == null) {
4954 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4955 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4962 if (best_operator == null)
4965 return best_operator.ConvertResult (ec, this);
4969 // Optimize & constant expressions with 0 value
4971 Expression OptimizeAndOperation (Expression expr)
4973 Constant rc = right as Constant;
4974 Constant lc = left as Constant;
4975 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4977 // The result is a constant with side-effect
4979 Constant side_effect = rc == null ?
4980 new SideEffectConstant (lc, right, loc) :
4981 new SideEffectConstant (rc, left, loc);
4983 return ReducedExpression.Create (side_effect, expr);
4990 // Value types can be compared with the null literal because of the lifting
4991 // language rules. However the result is always true or false.
4993 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4995 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4996 type = rc.BuiltinTypes.Bool;
5000 // FIXME: Handle side effect constants
5001 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5003 if ((Oper & Operator.EqualityMask) != 0) {
5004 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5005 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5007 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5008 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5015 // Performs user-operator overloading
5017 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5019 Expression oper_expr;
5021 var op = ConvertBinaryToUserOperator (oper);
5023 if (l.IsNullableType)
5024 l = Nullable.NullableInfo.GetUnderlyingType (l);
5026 if (r.IsNullableType)
5027 r = Nullable.NullableInfo.GetUnderlyingType (r);
5029 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5030 IList<MemberSpec> right_operators = null;
5033 right_operators = MemberCache.GetUserOperator (r, op, false);
5034 if (right_operators == null && left_operators == null)
5036 } else if (left_operators == null) {
5040 Arguments args = new Arguments (2);
5041 Argument larg = new Argument (left);
5043 Argument rarg = new Argument (right);
5047 // User-defined operator implementations always take precedence
5048 // over predefined operator implementations
5050 if (left_operators != null && right_operators != null) {
5051 left_operators = CombineUserOperators (left_operators, right_operators);
5052 } else if (right_operators != null) {
5053 left_operators = right_operators;
5056 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5057 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5059 var res = new OverloadResolver (left_operators, restr, loc);
5061 var oper_method = res.ResolveOperator (rc, ref args);
5062 if (oper_method == null) {
5064 // Logical && and || cannot be lifted
5066 if ((oper & Operator.LogicalMask) != 0)
5070 // Apply lifted user operators only for liftable types. Implicit conversion
5071 // to nullable types is not allowed
5073 if (!IsLiftedOperatorApplicable ())
5076 // TODO: Cache the result in module container
5077 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5078 if (lifted_methods == null)
5081 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5083 oper_method = res.ResolveOperator (rc, ref args);
5084 if (oper_method == null)
5087 MethodSpec best_original = null;
5088 foreach (MethodSpec ms in left_operators) {
5089 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5095 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5097 // Expression trees use lifted notation in this case
5099 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5100 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5103 var ptypes = best_original.Parameters.Types;
5105 if (left.IsNull || right.IsNull) {
5107 // The lifted operator produces a null value if one or both operands are null
5109 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5110 type = oper_method.ReturnType;
5111 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5115 // The lifted operator produces the value false if one or both operands are null for
5116 // relational operators.
5118 if ((oper & Operator.RelationalMask) != 0) {
5120 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5121 // because return type is actually bool
5123 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5126 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5127 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5131 type = oper_method.ReturnType;
5132 var lifted = new Nullable.LiftedBinaryOperator (this);
5133 lifted.UserOperator = best_original;
5135 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5136 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5139 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5140 lifted.UnwrapRight = new Nullable.Unwrap (right);
5143 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5144 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5146 return lifted.Resolve (rc);
5149 if ((oper & Operator.LogicalMask) != 0) {
5150 // TODO: CreateExpressionTree is allocated every time
5151 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5152 oper == Operator.LogicalAnd, loc).Resolve (rc);
5154 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5157 this.left = larg.Expr;
5158 this.right = rarg.Expr;
5163 bool IsLiftedOperatorApplicable ()
5165 if (left.Type.IsNullableType) {
5166 if ((oper & Operator.EqualityMask) != 0)
5167 return !right.IsNull;
5172 if (right.Type.IsNullableType) {
5173 if ((oper & Operator.EqualityMask) != 0)
5174 return !left.IsNull;
5179 if (TypeSpec.IsValueType (left.Type))
5180 return right.IsNull;
5182 if (TypeSpec.IsValueType (right.Type))
5188 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5190 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5191 if (nullable_type == null)
5195 // Lifted operators permit predefined and user-defined operators that operate
5196 // on non-nullable value types to also be used with nullable forms of those types.
5197 // Lifted operators are constructed from predefined and user-defined operators
5198 // that meet certain requirements
5200 List<MemberSpec> lifted = null;
5201 foreach (MethodSpec oper in operators) {
5203 if ((Oper & Operator.ComparisonMask) != 0) {
5205 // Result type must be of type bool for lifted comparison operators
5207 rt = oper.ReturnType;
5208 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5211 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5217 var ptypes = oper.Parameters.Types;
5218 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5222 // LAMESPEC: I am not sure why but for equality operators to be lifted
5223 // both types have to match
5225 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5229 lifted = new List<MemberSpec> ();
5232 // The lifted form is constructed by adding a single ? modifier to each operand and
5233 // result type except for comparison operators where return type is bool
5236 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5238 var parameters = ParametersCompiled.CreateFullyResolved (
5239 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5240 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5242 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5243 rt, parameters, oper.Modifiers);
5245 lifted.Add (lifted_op);
5252 // Merge two sets of user operators into one, they are mostly distinguish
5253 // except when they share base type and it contains an operator
5255 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5257 var combined = new List<MemberSpec> (left.Count + right.Count);
5258 combined.AddRange (left);
5259 foreach (var r in right) {
5261 foreach (var l in left) {
5262 if (l.DeclaringType == r.DeclaringType) {
5275 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5277 if (c is IntegralConstant || c is CharConstant) {
5279 c.ConvertExplicitly (true, type);
5280 } catch (OverflowException) {
5281 ec.Report.Warning (652, 2, loc,
5282 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5283 type.GetSignatureForError ());
5289 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5290 /// context of a conditional bool expression. This function will return
5291 /// false if it is was possible to use EmitBranchable, or true if it was.
5293 /// The expression's code is generated, and we will generate a branch to `target'
5294 /// if the resulting expression value is equal to isTrue
5296 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5298 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5299 left = left.EmitToField (ec);
5301 if ((oper & Operator.LogicalMask) == 0) {
5302 right = right.EmitToField (ec);
5307 // This is more complicated than it looks, but its just to avoid
5308 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5309 // but on top of that we want for == and != to use a special path
5310 // if we are comparing against null
5312 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5313 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5316 // put the constant on the rhs, for simplicity
5318 if (left is Constant) {
5319 Expression swap = right;
5325 // brtrue/brfalse works with native int only
5327 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5328 left.EmitBranchable (ec, target, my_on_true);
5331 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5332 // right is a boolean, and it's not 'false' => it is 'true'
5333 left.EmitBranchable (ec, target, !my_on_true);
5337 } else if (oper == Operator.LogicalAnd) {
5340 Label tests_end = ec.DefineLabel ();
5342 left.EmitBranchable (ec, tests_end, false);
5343 right.EmitBranchable (ec, target, true);
5344 ec.MarkLabel (tests_end);
5347 // This optimizes code like this
5348 // if (true && i > 4)
5350 if (!(left is Constant))
5351 left.EmitBranchable (ec, target, false);
5353 if (!(right is Constant))
5354 right.EmitBranchable (ec, target, false);
5359 } else if (oper == Operator.LogicalOr){
5361 left.EmitBranchable (ec, target, true);
5362 right.EmitBranchable (ec, target, true);
5365 Label tests_end = ec.DefineLabel ();
5366 left.EmitBranchable (ec, tests_end, true);
5367 right.EmitBranchable (ec, target, false);
5368 ec.MarkLabel (tests_end);
5373 } else if ((oper & Operator.ComparisonMask) == 0) {
5374 base.EmitBranchable (ec, target, on_true);
5381 TypeSpec t = left.Type;
5382 bool is_float = IsFloat (t);
5383 bool is_unsigned = is_float || IsUnsigned (t);
5386 case Operator.Equality:
5388 ec.Emit (OpCodes.Beq, target);
5390 ec.Emit (OpCodes.Bne_Un, target);
5393 case Operator.Inequality:
5395 ec.Emit (OpCodes.Bne_Un, target);
5397 ec.Emit (OpCodes.Beq, target);
5400 case Operator.LessThan:
5402 if (is_unsigned && !is_float)
5403 ec.Emit (OpCodes.Blt_Un, target);
5405 ec.Emit (OpCodes.Blt, target);
5408 ec.Emit (OpCodes.Bge_Un, target);
5410 ec.Emit (OpCodes.Bge, target);
5413 case Operator.GreaterThan:
5415 if (is_unsigned && !is_float)
5416 ec.Emit (OpCodes.Bgt_Un, target);
5418 ec.Emit (OpCodes.Bgt, target);
5421 ec.Emit (OpCodes.Ble_Un, target);
5423 ec.Emit (OpCodes.Ble, target);
5426 case Operator.LessThanOrEqual:
5428 if (is_unsigned && !is_float)
5429 ec.Emit (OpCodes.Ble_Un, target);
5431 ec.Emit (OpCodes.Ble, target);
5434 ec.Emit (OpCodes.Bgt_Un, target);
5436 ec.Emit (OpCodes.Bgt, target);
5440 case Operator.GreaterThanOrEqual:
5442 if (is_unsigned && !is_float)
5443 ec.Emit (OpCodes.Bge_Un, target);
5445 ec.Emit (OpCodes.Bge, target);
5448 ec.Emit (OpCodes.Blt_Un, target);
5450 ec.Emit (OpCodes.Blt, target);
5453 throw new InternalErrorException (oper.ToString ());
5457 public override void Emit (EmitContext ec)
5459 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5460 left = left.EmitToField (ec);
5462 if ((oper & Operator.LogicalMask) == 0) {
5463 right = right.EmitToField (ec);
5468 // Handle short-circuit operators differently
5471 if ((oper & Operator.LogicalMask) != 0) {
5472 Label load_result = ec.DefineLabel ();
5473 Label end = ec.DefineLabel ();
5475 bool is_or = oper == Operator.LogicalOr;
5476 left.EmitBranchable (ec, load_result, is_or);
5478 ec.Emit (OpCodes.Br_S, end);
5480 ec.MarkLabel (load_result);
5481 ec.EmitInt (is_or ? 1 : 0);
5487 // Optimize zero-based operations which cannot be optimized at expression level
5489 if (oper == Operator.Subtraction) {
5490 var lc = left as IntegralConstant;
5491 if (lc != null && lc.IsDefaultValue) {
5493 ec.Emit (OpCodes.Neg);
5498 EmitOperator (ec, left, right);
5501 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5506 EmitOperatorOpcode (ec, oper, left.Type, right);
5509 // Emit result enumerable conversion this way because it's quite complicated get it
5510 // to resolved tree because expression tree cannot see it.
5512 if (enum_conversion != 0)
5513 ConvCast.Emit (ec, enum_conversion);
5516 public override void EmitSideEffect (EmitContext ec)
5518 if ((oper & Operator.LogicalMask) != 0 ||
5519 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5520 base.EmitSideEffect (ec);
5522 left.EmitSideEffect (ec);
5523 right.EmitSideEffect (ec);
5527 public override Expression EmitToField (EmitContext ec)
5529 if ((oper & Operator.LogicalMask) == 0) {
5530 var await_expr = left as Await;
5531 if (await_expr != null && right.IsSideEffectFree) {
5532 await_expr.Statement.EmitPrologue (ec);
5533 left = await_expr.Statement.GetResultExpression (ec);
5537 await_expr = right as Await;
5538 if (await_expr != null && left.IsSideEffectFree) {
5539 await_expr.Statement.EmitPrologue (ec);
5540 right = await_expr.Statement.GetResultExpression (ec);
5545 return base.EmitToField (ec);
5548 protected override void CloneTo (CloneContext clonectx, Expression t)
5550 Binary target = (Binary) t;
5552 target.left = left.Clone (clonectx);
5553 target.right = right.Clone (clonectx);
5556 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5558 Arguments binder_args = new Arguments (4);
5560 MemberAccess sle = new MemberAccess (new MemberAccess (
5561 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5563 CSharpBinderFlags flags = 0;
5564 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5565 flags = CSharpBinderFlags.CheckedContext;
5567 if ((oper & Operator.LogicalMask) != 0)
5568 flags |= CSharpBinderFlags.BinaryOperationLogical;
5570 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5571 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5572 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5573 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5575 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5578 public override Expression CreateExpressionTree (ResolveContext ec)
5580 return CreateExpressionTree (ec, null);
5583 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5586 bool lift_arg = false;
5589 case Operator.Addition:
5590 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5591 method_name = "AddChecked";
5593 method_name = "Add";
5595 case Operator.BitwiseAnd:
5596 method_name = "And";
5598 case Operator.BitwiseOr:
5601 case Operator.Division:
5602 method_name = "Divide";
5604 case Operator.Equality:
5605 method_name = "Equal";
5608 case Operator.ExclusiveOr:
5609 method_name = "ExclusiveOr";
5611 case Operator.GreaterThan:
5612 method_name = "GreaterThan";
5615 case Operator.GreaterThanOrEqual:
5616 method_name = "GreaterThanOrEqual";
5619 case Operator.Inequality:
5620 method_name = "NotEqual";
5623 case Operator.LeftShift:
5624 method_name = "LeftShift";
5626 case Operator.LessThan:
5627 method_name = "LessThan";
5630 case Operator.LessThanOrEqual:
5631 method_name = "LessThanOrEqual";
5634 case Operator.LogicalAnd:
5635 method_name = "AndAlso";
5637 case Operator.LogicalOr:
5638 method_name = "OrElse";
5640 case Operator.Modulus:
5641 method_name = "Modulo";
5643 case Operator.Multiply:
5644 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5645 method_name = "MultiplyChecked";
5647 method_name = "Multiply";
5649 case Operator.RightShift:
5650 method_name = "RightShift";
5652 case Operator.Subtraction:
5653 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5654 method_name = "SubtractChecked";
5656 method_name = "Subtract";
5660 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5663 Arguments args = new Arguments (2);
5664 args.Add (new Argument (left.CreateExpressionTree (ec)));
5665 args.Add (new Argument (right.CreateExpressionTree (ec)));
5666 if (method != null) {
5668 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5670 args.Add (new Argument (method));
5673 return CreateExpressionFactoryCall (ec, method_name, args);
5676 public override object Accept (StructuralVisitor visitor)
5678 return visitor.Visit (this);
5684 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5685 // b, c, d... may be strings or objects.
5687 public class StringConcat : Expression
5689 Arguments arguments;
5691 StringConcat (Location loc)
5694 arguments = new Arguments (2);
5697 public override bool ContainsEmitWithAwait ()
5699 return arguments.ContainsEmitWithAwait ();
5702 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5704 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5705 throw new ArgumentException ();
5707 var s = new StringConcat (loc);
5708 s.type = rc.BuiltinTypes.String;
5709 s.eclass = ExprClass.Value;
5711 s.Append (rc, left);
5712 s.Append (rc, right);
5716 public override Expression CreateExpressionTree (ResolveContext ec)
5718 Argument arg = arguments [0];
5719 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5723 // Creates nested calls tree from an array of arguments used for IL emit
5725 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5727 Arguments concat_args = new Arguments (2);
5728 Arguments add_args = new Arguments (3);
5730 concat_args.Add (left);
5731 add_args.Add (new Argument (left_etree));
5733 concat_args.Add (arguments [pos]);
5734 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5736 var methods = GetConcatMethodCandidates ();
5737 if (methods == null)
5740 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5741 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5745 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5747 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5748 if (++pos == arguments.Count)
5751 left = new Argument (new EmptyExpression (method.ReturnType));
5752 return CreateExpressionAddCall (ec, left, expr, pos);
5755 protected override Expression DoResolve (ResolveContext ec)
5760 void Append (ResolveContext rc, Expression operand)
5765 StringConstant sc = operand as StringConstant;
5767 if (arguments.Count != 0) {
5768 Argument last_argument = arguments [arguments.Count - 1];
5769 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5770 if (last_expr_constant != null) {
5771 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5777 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5779 StringConcat concat_oper = operand as StringConcat;
5780 if (concat_oper != null) {
5781 arguments.AddRange (concat_oper.arguments);
5786 arguments.Add (new Argument (operand));
5789 IList<MemberSpec> GetConcatMethodCandidates ()
5791 return MemberCache.FindMembers (type, "Concat", true);
5794 public override void Emit (EmitContext ec)
5796 // Optimize by removing any extra null arguments, they are no-op
5797 for (int i = 0; i < arguments.Count; ++i) {
5798 if (arguments[i].Expr is NullConstant)
5799 arguments.RemoveAt (i--);
5802 var members = GetConcatMethodCandidates ();
5803 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5804 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5805 if (method != null) {
5806 var call = new CallEmitter ();
5807 call.EmitPredefined (ec, method, arguments, false);
5811 public override void FlowAnalysis (FlowAnalysisContext fc)
5813 arguments.FlowAnalysis (fc);
5816 public override SLE.Expression MakeExpression (BuilderContext ctx)
5818 if (arguments.Count != 2)
5819 throw new NotImplementedException ("arguments.Count != 2");
5821 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5822 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5827 // User-defined conditional logical operator
5829 public class ConditionalLogicalOperator : UserOperatorCall
5831 readonly bool is_and;
5832 Expression oper_expr;
5834 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5835 : base (oper, arguments, expr_tree, loc)
5837 this.is_and = is_and;
5838 eclass = ExprClass.Unresolved;
5841 protected override Expression DoResolve (ResolveContext ec)
5843 AParametersCollection pd = oper.Parameters;
5844 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5845 ec.Report.Error (217, loc,
5846 "A user-defined operator `{0}' must have each parameter type and return type of the same type in order to be applicable as a short circuit operator",
5847 oper.GetSignatureForError ());
5851 Expression left_dup = new EmptyExpression (type);
5852 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5853 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5854 if (op_true == null || op_false == null) {
5855 ec.Report.Error (218, loc,
5856 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5857 type.GetSignatureForError (), oper.GetSignatureForError ());
5861 oper_expr = is_and ? op_false : op_true;
5862 eclass = ExprClass.Value;
5866 public override void Emit (EmitContext ec)
5868 Label end_target = ec.DefineLabel ();
5871 // Emit and duplicate left argument
5873 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5874 if (right_contains_await) {
5875 arguments[0] = arguments[0].EmitToField (ec, false);
5876 arguments[0].Expr.Emit (ec);
5878 arguments[0].Expr.Emit (ec);
5879 ec.Emit (OpCodes.Dup);
5880 arguments.RemoveAt (0);
5883 oper_expr.EmitBranchable (ec, end_target, true);
5887 if (right_contains_await) {
5889 // Special handling when right expression contains await and left argument
5890 // could not be left on stack before logical branch
5892 Label skip_left_load = ec.DefineLabel ();
5893 ec.Emit (OpCodes.Br_S, skip_left_load);
5894 ec.MarkLabel (end_target);
5895 arguments[0].Expr.Emit (ec);
5896 ec.MarkLabel (skip_left_load);
5898 ec.MarkLabel (end_target);
5903 public class PointerArithmetic : Expression {
5904 Expression left, right;
5905 readonly Binary.Operator op;
5908 // We assume that `l' is always a pointer
5910 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5919 public override bool ContainsEmitWithAwait ()
5921 throw new NotImplementedException ();
5924 public override Expression CreateExpressionTree (ResolveContext ec)
5926 Error_PointerInsideExpressionTree (ec);
5930 protected override Expression DoResolve (ResolveContext ec)
5932 eclass = ExprClass.Variable;
5934 var pc = left.Type as PointerContainer;
5935 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5936 Error_VoidPointerOperation (ec);
5943 public override void Emit (EmitContext ec)
5945 TypeSpec op_type = left.Type;
5947 // It must be either array or fixed buffer
5949 if (TypeManager.HasElementType (op_type)) {
5950 element = TypeManager.GetElementType (op_type);
5952 FieldExpr fe = left as FieldExpr;
5954 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5959 int size = BuiltinTypeSpec.GetSize(element);
5960 TypeSpec rtype = right.Type;
5962 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5964 // handle (pointer - pointer)
5968 ec.Emit (OpCodes.Sub);
5972 ec.Emit (OpCodes.Sizeof, element);
5975 ec.Emit (OpCodes.Div);
5977 ec.Emit (OpCodes.Conv_I8);
5980 // handle + and - on (pointer op int)
5982 Constant left_const = left as Constant;
5983 if (left_const != null) {
5985 // Optimize ((T*)null) pointer operations
5987 if (left_const.IsDefaultValue) {
5988 left = EmptyExpression.Null;
5996 var right_const = right as Constant;
5997 if (right_const != null) {
5999 // Optimize 0-based arithmetic
6001 if (right_const.IsDefaultValue)
6005 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6007 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6009 // TODO: Should be the checks resolve context sensitive?
6010 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6011 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6017 if (right_const == null) {
6018 switch (rtype.BuiltinType) {
6019 case BuiltinTypeSpec.Type.SByte:
6020 case BuiltinTypeSpec.Type.Byte:
6021 case BuiltinTypeSpec.Type.Short:
6022 case BuiltinTypeSpec.Type.UShort:
6023 case BuiltinTypeSpec.Type.Int:
6024 ec.Emit (OpCodes.Conv_I);
6026 case BuiltinTypeSpec.Type.UInt:
6027 ec.Emit (OpCodes.Conv_U);
6032 if (right_const == null && size != 1){
6034 ec.Emit (OpCodes.Sizeof, element);
6037 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6038 ec.Emit (OpCodes.Conv_I8);
6040 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6043 if (left_const == null) {
6044 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6045 ec.Emit (OpCodes.Conv_I);
6046 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6047 ec.Emit (OpCodes.Conv_U);
6049 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6056 // A boolean-expression is an expression that yields a result
6059 public class BooleanExpression : ShimExpression
6061 public BooleanExpression (Expression expr)
6064 this.loc = expr.Location;
6067 public override Expression CreateExpressionTree (ResolveContext ec)
6069 // TODO: We should emit IsTrue (v4) instead of direct user operator
6070 // call but that would break csc compatibility
6071 return base.CreateExpressionTree (ec);
6074 protected override Expression DoResolve (ResolveContext ec)
6076 // A boolean-expression is required to be of a type
6077 // that can be implicitly converted to bool or of
6078 // a type that implements operator true
6080 expr = expr.Resolve (ec);
6084 Assign ass = expr as Assign;
6085 if (ass != null && ass.Source is Constant) {
6086 ec.Report.Warning (665, 3, loc,
6087 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6090 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6093 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6094 Arguments args = new Arguments (1);
6095 args.Add (new Argument (expr));
6096 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6099 type = ec.BuiltinTypes.Bool;
6100 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6101 if (converted != null)
6105 // If no implicit conversion to bool exists, try using `operator true'
6107 converted = GetOperatorTrue (ec, expr, loc);
6108 if (converted == null) {
6109 expr.Error_ValueCannotBeConverted (ec, type, false);
6116 public override object Accept (StructuralVisitor visitor)
6118 return visitor.Visit (this);
6122 public class BooleanExpressionFalse : Unary
6124 public BooleanExpressionFalse (Expression expr)
6125 : base (Operator.LogicalNot, expr, expr.Location)
6129 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6131 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6136 /// Implements the ternary conditional operator (?:)
6138 public class Conditional : Expression {
6139 Expression expr, true_expr, false_expr;
6141 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6144 this.true_expr = true_expr;
6145 this.false_expr = false_expr;
6151 public Expression Expr {
6157 public Expression TrueExpr {
6163 public Expression FalseExpr {
6171 public override bool ContainsEmitWithAwait ()
6173 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6176 public override Expression CreateExpressionTree (ResolveContext ec)
6178 Arguments args = new Arguments (3);
6179 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6180 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6181 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6182 return CreateExpressionFactoryCall (ec, "Condition", args);
6185 protected override Expression DoResolve (ResolveContext ec)
6187 expr = expr.Resolve (ec);
6188 true_expr = true_expr.Resolve (ec);
6189 false_expr = false_expr.Resolve (ec);
6191 if (true_expr == null || false_expr == null || expr == null)
6194 eclass = ExprClass.Value;
6195 TypeSpec true_type = true_expr.Type;
6196 TypeSpec false_type = false_expr.Type;
6200 // First, if an implicit conversion exists from true_expr
6201 // to false_expr, then the result type is of type false_expr.Type
6203 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6204 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6205 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6207 // Check if both can convert implicitly to each other's type
6211 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6212 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6214 // LAMESPEC: There seems to be hardcoded promotition to int type when
6215 // both sides are numeric constants and one side is int constant and
6216 // other side is numeric constant convertible to int.
6218 // var res = condition ? (short)1 : 1;
6220 // Type of res is int even if according to the spec the conversion is
6221 // ambiguous because 1 literal can be converted to short.
6223 if (conv_false_expr != null) {
6224 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6226 conv_false_expr = null;
6227 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6228 conv_false_expr = null;
6232 if (conv_false_expr != null) {
6233 ec.Report.Error (172, true_expr.Location,
6234 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6235 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6240 if (true_expr.Type != type)
6241 true_expr = EmptyCast.Create (true_expr, type);
6242 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6245 if (false_type != InternalType.ErrorType) {
6246 ec.Report.Error (173, true_expr.Location,
6247 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6248 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6254 Constant c = expr as Constant;
6256 bool is_false = c.IsDefaultValue;
6259 // Don't issue the warning for constant expressions
6261 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6262 // CSC: Missing warning
6263 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6266 return ReducedExpression.Create (
6267 is_false ? false_expr : true_expr, this,
6268 false_expr is Constant && true_expr is Constant).Resolve (ec);
6274 public override void Emit (EmitContext ec)
6276 Label false_target = ec.DefineLabel ();
6277 Label end_target = ec.DefineLabel ();
6279 expr.EmitBranchable (ec, false_target, false);
6280 true_expr.Emit (ec);
6283 // Verifier doesn't support interface merging. When there are two types on
6284 // the stack without common type hint and the common type is an interface.
6285 // Use temporary local to give verifier hint on what type to unify the stack
6287 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6288 var temp = ec.GetTemporaryLocal (type);
6289 ec.Emit (OpCodes.Stloc, temp);
6290 ec.Emit (OpCodes.Ldloc, temp);
6291 ec.FreeTemporaryLocal (temp, type);
6294 ec.Emit (OpCodes.Br, end_target);
6295 ec.MarkLabel (false_target);
6296 false_expr.Emit (ec);
6297 ec.MarkLabel (end_target);
6300 public override void FlowAnalysis (FlowAnalysisContext fc)
6302 expr.FlowAnalysisConditional (fc);
6303 var expr_true = fc.DefiniteAssignmentOnTrue;
6304 var expr_false = fc.DefiniteAssignmentOnFalse;
6306 fc.BranchDefiniteAssignment (expr_true);
6307 true_expr.FlowAnalysis (fc);
6308 var true_fc = fc.DefiniteAssignment;
6310 fc.BranchDefiniteAssignment (expr_false);
6311 false_expr.FlowAnalysis (fc);
6313 fc.DefiniteAssignment &= true_fc;
6316 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6318 expr.FlowAnalysisConditional (fc);
6319 var expr_true = fc.DefiniteAssignmentOnTrue;
6320 var expr_false = fc.DefiniteAssignmentOnFalse;
6322 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6323 true_expr.FlowAnalysisConditional (fc);
6324 var true_fc = fc.DefiniteAssignment;
6325 var true_da_true = fc.DefiniteAssignmentOnTrue;
6326 var true_da_false = fc.DefiniteAssignmentOnFalse;
6328 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6329 false_expr.FlowAnalysisConditional (fc);
6331 fc.DefiniteAssignment &= true_fc;
6332 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6333 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6336 protected override void CloneTo (CloneContext clonectx, Expression t)
6338 Conditional target = (Conditional) t;
6340 target.expr = expr.Clone (clonectx);
6341 target.true_expr = true_expr.Clone (clonectx);
6342 target.false_expr = false_expr.Clone (clonectx);
6346 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6348 LocalTemporary temp;
6351 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6352 public abstract void SetHasAddressTaken ();
6354 public abstract bool IsLockedByStatement { get; set; }
6356 public abstract bool IsFixed { get; }
6357 public abstract bool IsRef { get; }
6358 public abstract string Name { get; }
6361 // Variable IL data, it has to be protected to encapsulate hoisted variables
6363 protected abstract ILocalVariable Variable { get; }
6366 // Variable flow-analysis data
6368 public abstract VariableInfo VariableInfo { get; }
6371 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6373 HoistedVariable hv = GetHoistedVariable (ec);
6375 hv.AddressOf (ec, mode);
6379 Variable.EmitAddressOf (ec);
6382 public override bool ContainsEmitWithAwait ()
6387 public override Expression CreateExpressionTree (ResolveContext ec)
6389 HoistedVariable hv = GetHoistedVariable (ec);
6391 return hv.CreateExpressionTree ();
6393 Arguments arg = new Arguments (1);
6394 arg.Add (new Argument (this));
6395 return CreateExpressionFactoryCall (ec, "Constant", arg);
6398 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6400 if (IsLockedByStatement) {
6401 rc.Report.Warning (728, 2, loc,
6402 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6409 public override void Emit (EmitContext ec)
6414 public override void EmitSideEffect (EmitContext ec)
6420 // This method is used by parameters that are references, that are
6421 // being passed as references: we only want to pass the pointer (that
6422 // is already stored in the parameter, not the address of the pointer,
6423 // and not the value of the variable).
6425 public void EmitLoad (EmitContext ec)
6430 public void Emit (EmitContext ec, bool leave_copy)
6432 HoistedVariable hv = GetHoistedVariable (ec);
6434 hv.Emit (ec, leave_copy);
6442 // If we are a reference, we loaded on the stack a pointer
6443 // Now lets load the real value
6445 ec.EmitLoadFromPtr (type);
6449 ec.Emit (OpCodes.Dup);
6452 temp = new LocalTemporary (Type);
6458 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6459 bool prepare_for_load)
6461 HoistedVariable hv = GetHoistedVariable (ec);
6463 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6467 New n_source = source as New;
6468 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6469 if (!n_source.Emit (ec, this)) {
6473 ec.EmitLoadFromPtr (type);
6485 ec.Emit (OpCodes.Dup);
6487 temp = new LocalTemporary (Type);
6493 ec.EmitStoreFromPtr (type);
6495 Variable.EmitAssign (ec);
6503 public override Expression EmitToField (EmitContext ec)
6505 HoistedVariable hv = GetHoistedVariable (ec);
6507 return hv.EmitToField (ec);
6510 return base.EmitToField (ec);
6513 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6515 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6518 public HoistedVariable GetHoistedVariable (EmitContext ec)
6520 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6523 public override string GetSignatureForError ()
6528 public bool IsHoisted {
6529 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6534 // Resolved reference to a local variable
6536 public class LocalVariableReference : VariableReference
6538 public LocalVariable local_info;
6540 public LocalVariableReference (LocalVariable li, Location l)
6542 this.local_info = li;
6546 public override VariableInfo VariableInfo {
6547 get { return local_info.VariableInfo; }
6550 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6552 return local_info.HoistedVariant;
6558 // A local variable is always fixed
6560 public override bool IsFixed {
6566 public override bool IsLockedByStatement {
6568 return local_info.IsLocked;
6571 local_info.IsLocked = value;
6575 public override bool IsRef {
6576 get { return false; }
6579 public override string Name {
6580 get { return local_info.Name; }
6585 public override void FlowAnalysis (FlowAnalysisContext fc)
6587 VariableInfo variable_info = VariableInfo;
6588 if (variable_info == null)
6591 if (fc.IsDefinitelyAssigned (variable_info))
6594 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6595 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6598 public override void SetHasAddressTaken ()
6600 local_info.SetHasAddressTaken ();
6603 void DoResolveBase (ResolveContext ec)
6605 eclass = ExprClass.Variable;
6606 type = local_info.Type;
6609 // If we are referencing a variable from the external block
6610 // flag it for capturing
6612 if (ec.MustCaptureVariable (local_info)) {
6613 if (local_info.AddressTaken) {
6614 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6615 } else if (local_info.IsFixed) {
6616 ec.Report.Error (1764, loc,
6617 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6618 GetSignatureForError ());
6621 if (ec.IsVariableCapturingRequired) {
6622 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6623 storey.CaptureLocalVariable (ec, local_info);
6628 protected override Expression DoResolve (ResolveContext ec)
6630 local_info.SetIsUsed ();
6634 if (local_info.Type == InternalType.VarOutType) {
6635 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6636 GetSignatureForError ());
6638 type = InternalType.ErrorType;
6644 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6647 // Don't be too pedantic when variable is used as out param or for some broken code
6648 // which uses property/indexer access to run some initialization
6650 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6651 local_info.SetIsUsed ();
6653 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6654 if (rhs == EmptyExpression.LValueMemberAccess) {
6655 // CS1654 already reported
6659 if (rhs == EmptyExpression.OutAccess) {
6660 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6661 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6662 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6663 } else if (rhs == EmptyExpression.UnaryAddress) {
6664 code = 459; msg = "Cannot take the address of {1} `{0}'";
6666 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6668 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6672 if (eclass == ExprClass.Unresolved)
6675 return base.DoResolveLValue (ec, rhs);
6678 public override int GetHashCode ()
6680 return local_info.GetHashCode ();
6683 public override bool Equals (object obj)
6685 LocalVariableReference lvr = obj as LocalVariableReference;
6689 return local_info == lvr.local_info;
6692 protected override ILocalVariable Variable {
6693 get { return local_info; }
6696 public override string ToString ()
6698 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6701 protected override void CloneTo (CloneContext clonectx, Expression t)
6708 /// This represents a reference to a parameter in the intermediate
6711 public class ParameterReference : VariableReference
6713 protected ParametersBlock.ParameterInfo pi;
6715 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6723 public override bool IsLockedByStatement {
6728 pi.IsLocked = value;
6732 public override bool IsRef {
6733 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6736 bool HasOutModifier {
6737 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6740 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6742 return pi.Parameter.HoistedVariant;
6746 // A ref or out parameter is classified as a moveable variable, even
6747 // if the argument given for the parameter is a fixed variable
6749 public override bool IsFixed {
6750 get { return !IsRef; }
6753 public override string Name {
6754 get { return Parameter.Name; }
6757 public Parameter Parameter {
6758 get { return pi.Parameter; }
6761 public override VariableInfo VariableInfo {
6762 get { return pi.VariableInfo; }
6765 protected override ILocalVariable Variable {
6766 get { return Parameter; }
6771 public override void AddressOf (EmitContext ec, AddressOp mode)
6774 // ParameterReferences might already be a reference
6781 base.AddressOf (ec, mode);
6784 public override void SetHasAddressTaken ()
6786 Parameter.HasAddressTaken = true;
6789 bool DoResolveBase (ResolveContext ec)
6791 if (eclass != ExprClass.Unresolved)
6794 type = pi.ParameterType;
6795 eclass = ExprClass.Variable;
6798 // If we are referencing a parameter from the external block
6799 // flag it for capturing
6801 if (ec.MustCaptureVariable (pi)) {
6802 if (Parameter.HasAddressTaken)
6803 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6806 ec.Report.Error (1628, loc,
6807 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6808 Name, ec.CurrentAnonymousMethod.ContainerType);
6811 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6812 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6813 storey.CaptureParameter (ec, pi, this);
6820 public override int GetHashCode ()
6822 return Name.GetHashCode ();
6825 public override bool Equals (object obj)
6827 ParameterReference pr = obj as ParameterReference;
6831 return Name == pr.Name;
6834 protected override void CloneTo (CloneContext clonectx, Expression target)
6840 public override Expression CreateExpressionTree (ResolveContext ec)
6842 HoistedVariable hv = GetHoistedVariable (ec);
6844 return hv.CreateExpressionTree ();
6846 return Parameter.ExpressionTreeVariableReference ();
6849 protected override Expression DoResolve (ResolveContext ec)
6851 if (!DoResolveBase (ec))
6857 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6859 if (!DoResolveBase (ec))
6862 if (Parameter.HoistedVariant != null)
6863 Parameter.HoistedVariant.IsAssigned = true;
6865 return base.DoResolveLValue (ec, right_side);
6868 public override void FlowAnalysis (FlowAnalysisContext fc)
6870 VariableInfo variable_info = VariableInfo;
6871 if (variable_info == null)
6874 if (fc.IsDefinitelyAssigned (variable_info))
6877 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6878 fc.SetVariableAssigned (variable_info);
6883 /// Invocation of methods or delegates.
6885 public class Invocation : ExpressionStatement
6887 public class Predefined : Invocation
6889 public Predefined (MethodGroupExpr expr, Arguments arguments)
6890 : base (expr, arguments)
6895 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6897 mg.BestCandidate.CheckObsoleteness (rc, loc);
6903 protected Arguments arguments;
6904 protected Expression expr;
6905 protected MethodGroupExpr mg;
6906 bool conditional_access_receiver;
6908 public Invocation (Expression expr, Arguments arguments)
6911 this.arguments = arguments;
6913 loc = expr.Location;
6918 public Arguments Arguments {
6924 public Expression Exp {
6930 public MethodGroupExpr MethodGroup {
6936 public override Location StartLocation {
6938 return expr.StartLocation;
6944 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6946 if (MethodGroup == null)
6949 var candidate = MethodGroup.BestCandidate;
6950 if (candidate == null || !(candidate.IsStatic || Exp is This))
6953 var args_count = arguments == null ? 0 : arguments.Count;
6954 if (args_count != body.Parameters.Count)
6957 var lambda_parameters = body.Block.Parameters.FixedParameters;
6958 for (int i = 0; i < args_count; ++i) {
6959 var pr = arguments[i].Expr as ParameterReference;
6963 if (lambda_parameters[i] != pr.Parameter)
6966 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6970 var emg = MethodGroup as ExtensionMethodGroupExpr;
6972 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6973 if (candidate.IsGeneric) {
6974 var targs = new TypeExpression [candidate.Arity];
6975 for (int i = 0; i < targs.Length; ++i) {
6976 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6979 mg.SetTypeArguments (null, new TypeArguments (targs));
6988 protected override void CloneTo (CloneContext clonectx, Expression t)
6990 Invocation target = (Invocation) t;
6992 if (arguments != null)
6993 target.arguments = arguments.Clone (clonectx);
6995 target.expr = expr.Clone (clonectx);
6998 public override bool ContainsEmitWithAwait ()
7000 if (arguments != null && arguments.ContainsEmitWithAwait ())
7003 return mg.ContainsEmitWithAwait ();
7006 public override Expression CreateExpressionTree (ResolveContext ec)
7008 Expression instance = mg.IsInstance ?
7009 mg.InstanceExpression.CreateExpressionTree (ec) :
7010 new NullLiteral (loc);
7012 var args = Arguments.CreateForExpressionTree (ec, arguments,
7014 mg.CreateExpressionTree (ec));
7016 return CreateExpressionFactoryCall (ec, "Call", args);
7019 void ResolveConditionalAccessReceiver (ResolveContext rc)
7021 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7022 conditional_access_receiver = true;
7026 bool statement_resolve;
7027 public override ExpressionStatement ResolveStatement (BlockContext bc)
7029 statement_resolve = true;
7030 var es = base.ResolveStatement (bc);
7031 statement_resolve = false;
7036 protected override Expression DoResolve (ResolveContext rc)
7038 ResolveConditionalAccessReceiver (rc);
7039 return DoResolveInvocation (rc);
7042 Expression DoResolveInvocation (ResolveContext ec)
7044 Expression member_expr;
7045 var atn = expr as ATypeNameExpression;
7047 var flags = default (ResolveContext.FlagsHandle);
7048 if (conditional_access_receiver)
7049 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7052 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7053 if (member_expr != null) {
7054 var name_of = member_expr as NameOf;
7055 if (name_of != null) {
7056 return name_of.ResolveOverload (ec, arguments);
7059 member_expr = member_expr.Resolve (ec);
7062 member_expr = expr.Resolve (ec);
7065 if (conditional_access_receiver)
7068 if (member_expr == null)
7072 // Next, evaluate all the expressions in the argument list
7074 bool dynamic_arg = false;
7075 if (arguments != null) {
7076 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7077 arguments.Resolve (ec, out dynamic_arg);
7081 TypeSpec expr_type = member_expr.Type;
7082 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7083 return DoResolveDynamic (ec, member_expr);
7085 mg = member_expr as MethodGroupExpr;
7086 Expression invoke = null;
7089 if (expr_type != null && expr_type.IsDelegate) {
7090 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7091 invoke = invoke.Resolve (ec);
7092 if (invoke == null || !dynamic_arg)
7095 if (member_expr is RuntimeValueExpression) {
7096 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7097 member_expr.Type.GetSignatureForError ());
7101 MemberExpr me = member_expr as MemberExpr;
7103 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7107 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7108 member_expr.GetSignatureForError ());
7113 if (invoke == null) {
7114 mg = DoResolveOverload (ec);
7120 return DoResolveDynamic (ec, member_expr);
7122 var method = mg.BestCandidate;
7123 type = mg.BestCandidateReturnType;
7124 if (conditional_access_receiver && !statement_resolve)
7125 type = LiftMemberType (ec, type);
7127 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7129 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7131 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7135 IsSpecialMethodInvocation (ec, method, loc);
7137 eclass = ExprClass.Value;
7141 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7144 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7146 args = dmb.Arguments;
7147 if (arguments != null)
7148 args.AddRange (arguments);
7149 } else if (mg == null) {
7150 if (arguments == null)
7151 args = new Arguments (1);
7155 args.Insert (0, new Argument (memberExpr));
7159 ec.Report.Error (1971, loc,
7160 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7165 if (arguments == null)
7166 args = new Arguments (1);
7170 MemberAccess ma = expr as MemberAccess;
7172 var inst = mg.InstanceExpression;
7173 var left_type = inst as TypeExpr;
7174 if (left_type != null) {
7175 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7176 } else if (inst != null) {
7178 // Any value type has to be pass as by-ref to get back the same
7179 // instance on which the member was called
7181 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7182 Argument.AType.Ref : Argument.AType.None;
7183 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7185 } else { // is SimpleName
7186 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7187 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7189 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7194 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7197 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7199 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7202 public override void FlowAnalysis (FlowAnalysisContext fc)
7204 if (mg.IsConditionallyExcluded)
7207 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7209 mg.FlowAnalysis (fc);
7211 if (arguments != null)
7212 arguments.FlowAnalysis (fc);
7214 if (conditional_access_receiver)
7215 fc.DefiniteAssignment = da;
7218 public override string GetSignatureForError ()
7220 return mg.GetSignatureForError ();
7223 public override bool HasConditionalAccess ()
7225 return expr.HasConditionalAccess ();
7229 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7230 // or the type dynamic, then the member is invocable
7232 public static bool IsMemberInvocable (MemberSpec member)
7234 switch (member.Kind) {
7235 case MemberKind.Event:
7237 case MemberKind.Field:
7238 case MemberKind.Property:
7239 var m = member as IInterfaceMemberSpec;
7240 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7246 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7248 if (!method.IsReservedMethod)
7251 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7254 ec.Report.SymbolRelatedToPreviousError (method);
7255 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7256 method.GetSignatureForError ());
7261 public override void Emit (EmitContext ec)
7263 if (mg.IsConditionallyExcluded)
7266 if (conditional_access_receiver)
7267 mg.EmitCall (ec, arguments, type, false);
7269 mg.EmitCall (ec, arguments, false);
7272 public override void EmitStatement (EmitContext ec)
7274 if (mg.IsConditionallyExcluded)
7277 if (conditional_access_receiver)
7278 mg.EmitCall (ec, arguments, type, true);
7280 mg.EmitCall (ec, arguments, true);
7283 public override SLE.Expression MakeExpression (BuilderContext ctx)
7285 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7288 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7291 throw new NotSupportedException ();
7293 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7294 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7298 public override object Accept (StructuralVisitor visitor)
7300 return visitor.Visit (this);
7305 // Implements simple new expression
7307 public class New : ExpressionStatement, IMemoryLocation
7309 protected Arguments arguments;
7312 // During bootstrap, it contains the RequestedType,
7313 // but if `type' is not null, it *might* contain a NewDelegate
7314 // (because of field multi-initialization)
7316 protected Expression RequestedType;
7318 protected MethodSpec method;
7320 public New (Expression requested_type, Arguments arguments, Location l)
7322 RequestedType = requested_type;
7323 this.arguments = arguments;
7328 public Arguments Arguments {
7335 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7337 public bool IsGeneratedStructConstructor {
7339 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7343 public Expression TypeExpression {
7345 return RequestedType;
7352 /// Converts complex core type syntax like 'new int ()' to simple constant
7354 public static Constant Constantify (TypeSpec t, Location loc)
7356 switch (t.BuiltinType) {
7357 case BuiltinTypeSpec.Type.Int:
7358 return new IntConstant (t, 0, loc);
7359 case BuiltinTypeSpec.Type.UInt:
7360 return new UIntConstant (t, 0, loc);
7361 case BuiltinTypeSpec.Type.Long:
7362 return new LongConstant (t, 0, loc);
7363 case BuiltinTypeSpec.Type.ULong:
7364 return new ULongConstant (t, 0, loc);
7365 case BuiltinTypeSpec.Type.Float:
7366 return new FloatConstant (t, 0, loc);
7367 case BuiltinTypeSpec.Type.Double:
7368 return new DoubleConstant (t, 0, loc);
7369 case BuiltinTypeSpec.Type.Short:
7370 return new ShortConstant (t, 0, loc);
7371 case BuiltinTypeSpec.Type.UShort:
7372 return new UShortConstant (t, 0, loc);
7373 case BuiltinTypeSpec.Type.SByte:
7374 return new SByteConstant (t, 0, loc);
7375 case BuiltinTypeSpec.Type.Byte:
7376 return new ByteConstant (t, 0, loc);
7377 case BuiltinTypeSpec.Type.Char:
7378 return new CharConstant (t, '\0', loc);
7379 case BuiltinTypeSpec.Type.Bool:
7380 return new BoolConstant (t, false, loc);
7381 case BuiltinTypeSpec.Type.Decimal:
7382 return new DecimalConstant (t, 0, loc);
7386 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7388 if (t.IsNullableType)
7389 return Nullable.LiftedNull.Create (t, loc);
7394 public override bool ContainsEmitWithAwait ()
7396 return arguments != null && arguments.ContainsEmitWithAwait ();
7400 // Checks whether the type is an interface that has the
7401 // [ComImport, CoClass] attributes and must be treated
7404 public Expression CheckComImport (ResolveContext ec)
7406 if (!type.IsInterface)
7410 // Turn the call into:
7411 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7413 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7414 if (real_class == null)
7417 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7418 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7419 return cast.Resolve (ec);
7422 public override Expression CreateExpressionTree (ResolveContext ec)
7425 if (method == null) {
7426 args = new Arguments (1);
7427 args.Add (new Argument (new TypeOf (type, loc)));
7429 args = Arguments.CreateForExpressionTree (ec,
7430 arguments, new TypeOfMethod (method, loc));
7433 return CreateExpressionFactoryCall (ec, "New", args);
7436 protected override Expression DoResolve (ResolveContext ec)
7438 type = RequestedType.ResolveAsType (ec);
7442 eclass = ExprClass.Value;
7444 if (type.IsPointer) {
7445 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7446 type.GetSignatureForError ());
7450 if (arguments == null) {
7451 Constant c = Constantify (type, RequestedType.Location);
7453 return ReducedExpression.Create (c, this);
7456 if (type.IsDelegate) {
7457 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7460 var tparam = type as TypeParameterSpec;
7461 if (tparam != null) {
7463 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7464 // where type parameter constraint is inflated to struct
7466 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7467 ec.Report.Error (304, loc,
7468 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7469 type.GetSignatureForError ());
7472 if ((arguments != null) && (arguments.Count != 0)) {
7473 ec.Report.Error (417, loc,
7474 "`{0}': cannot provide arguments when creating an instance of a variable type",
7475 type.GetSignatureForError ());
7481 if (type.IsStatic) {
7482 ec.Report.SymbolRelatedToPreviousError (type);
7483 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7487 if (type.IsInterface || type.IsAbstract){
7488 if (!TypeManager.IsGenericType (type)) {
7489 RequestedType = CheckComImport (ec);
7490 if (RequestedType != null)
7491 return RequestedType;
7494 ec.Report.SymbolRelatedToPreviousError (type);
7495 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7500 if (arguments != null) {
7501 arguments.Resolve (ec, out dynamic);
7506 method = ConstructorLookup (ec, type, ref arguments, loc);
7509 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7510 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7516 void DoEmitTypeParameter (EmitContext ec)
7518 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7522 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7523 ec.Emit (OpCodes.Call, ctor_factory);
7527 // This Emit can be invoked in two contexts:
7528 // * As a mechanism that will leave a value on the stack (new object)
7529 // * As one that wont (init struct)
7531 // If we are dealing with a ValueType, we have a few
7532 // situations to deal with:
7534 // * The target is a ValueType, and we have been provided
7535 // the instance (this is easy, we are being assigned).
7537 // * The target of New is being passed as an argument,
7538 // to a boxing operation or a function that takes a
7541 // In this case, we need to create a temporary variable
7542 // that is the argument of New.
7544 // Returns whether a value is left on the stack
7546 // *** Implementation note ***
7548 // To benefit from this optimization, each assignable expression
7549 // has to manually cast to New and call this Emit.
7551 // TODO: It's worth to implement it for arrays and fields
7553 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7555 bool is_value_type = type.IsStructOrEnum;
7556 VariableReference vr = target as VariableReference;
7558 if (target != null && is_value_type && (vr != null || method == null)) {
7559 target.AddressOf (ec, AddressOp.Store);
7560 } else if (vr != null && vr.IsRef) {
7564 if (arguments != null) {
7565 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7566 arguments = arguments.Emit (ec, false, true);
7568 arguments.Emit (ec);
7571 if (is_value_type) {
7572 if (method == null) {
7573 ec.Emit (OpCodes.Initobj, type);
7578 ec.MarkCallEntry (loc);
7579 ec.Emit (OpCodes.Call, method);
7584 if (type is TypeParameterSpec) {
7585 DoEmitTypeParameter (ec);
7589 ec.MarkCallEntry (loc);
7590 ec.Emit (OpCodes.Newobj, method);
7594 public override void Emit (EmitContext ec)
7596 LocalTemporary v = null;
7597 if (method == null && type.IsStructOrEnum) {
7598 // TODO: Use temporary variable from pool
7599 v = new LocalTemporary (type);
7606 public override void EmitStatement (EmitContext ec)
7608 LocalTemporary v = null;
7609 if (method == null && TypeSpec.IsValueType (type)) {
7610 // TODO: Use temporary variable from pool
7611 v = new LocalTemporary (type);
7615 ec.Emit (OpCodes.Pop);
7618 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7623 public override void FlowAnalysis (FlowAnalysisContext fc)
7625 if (arguments != null)
7626 arguments.FlowAnalysis (fc);
7629 public void AddressOf (EmitContext ec, AddressOp mode)
7631 EmitAddressOf (ec, mode);
7634 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7636 LocalTemporary value_target = new LocalTemporary (type);
7638 if (type is TypeParameterSpec) {
7639 DoEmitTypeParameter (ec);
7640 value_target.Store (ec);
7641 value_target.AddressOf (ec, mode);
7642 return value_target;
7645 value_target.AddressOf (ec, AddressOp.Store);
7647 if (method == null) {
7648 ec.Emit (OpCodes.Initobj, type);
7650 if (arguments != null)
7651 arguments.Emit (ec);
7653 ec.Emit (OpCodes.Call, method);
7656 value_target.AddressOf (ec, mode);
7657 return value_target;
7660 protected override void CloneTo (CloneContext clonectx, Expression t)
7662 New target = (New) t;
7664 target.RequestedType = RequestedType.Clone (clonectx);
7665 if (arguments != null){
7666 target.arguments = arguments.Clone (clonectx);
7670 public override SLE.Expression MakeExpression (BuilderContext ctx)
7673 return base.MakeExpression (ctx);
7675 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7679 public override object Accept (StructuralVisitor visitor)
7681 return visitor.Visit (this);
7686 // Array initializer expression, the expression is allowed in
7687 // variable or field initialization only which makes it tricky as
7688 // the type has to be infered based on the context either from field
7689 // type or variable type (think of multiple declarators)
7691 public class ArrayInitializer : Expression
7693 List<Expression> elements;
7694 BlockVariable variable;
7696 public ArrayInitializer (List<Expression> init, Location loc)
7702 public ArrayInitializer (int count, Location loc)
7703 : this (new List<Expression> (count), loc)
7707 public ArrayInitializer (Location loc)
7715 get { return elements.Count; }
7718 public List<Expression> Elements {
7724 public Expression this [int index] {
7726 return elements [index];
7730 public BlockVariable VariableDeclaration {
7741 public void Add (Expression expr)
7743 elements.Add (expr);
7746 public override bool ContainsEmitWithAwait ()
7748 throw new NotSupportedException ();
7751 public override Expression CreateExpressionTree (ResolveContext ec)
7753 throw new NotSupportedException ("ET");
7756 protected override void CloneTo (CloneContext clonectx, Expression t)
7758 var target = (ArrayInitializer) t;
7760 target.elements = new List<Expression> (elements.Count);
7761 foreach (var element in elements)
7762 target.elements.Add (element.Clone (clonectx));
7765 protected override Expression DoResolve (ResolveContext rc)
7767 var current_field = rc.CurrentMemberDefinition as FieldBase;
7768 TypeExpression type;
7769 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7770 type = new TypeExpression (current_field.MemberType, current_field.Location);
7771 } else if (variable != null) {
7772 if (variable.TypeExpression is VarExpr) {
7773 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7774 return EmptyExpression.Null;
7777 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7779 throw new NotImplementedException ("Unexpected array initializer context");
7782 return new ArrayCreation (type, this).Resolve (rc);
7785 public override void Emit (EmitContext ec)
7787 throw new InternalErrorException ("Missing Resolve call");
7790 public override void FlowAnalysis (FlowAnalysisContext fc)
7792 throw new InternalErrorException ("Missing Resolve call");
7795 public override object Accept (StructuralVisitor visitor)
7797 return visitor.Visit (this);
7802 /// 14.5.10.2: Represents an array creation expression.
7806 /// There are two possible scenarios here: one is an array creation
7807 /// expression that specifies the dimensions and optionally the
7808 /// initialization data and the other which does not need dimensions
7809 /// specified but where initialization data is mandatory.
7811 public class ArrayCreation : Expression
7813 FullNamedExpression requested_base_type;
7814 ArrayInitializer initializers;
7817 // The list of Argument types.
7818 // This is used to construct the `newarray' or constructor signature
7820 protected List<Expression> arguments;
7822 protected TypeSpec array_element_type;
7824 protected int dimensions;
7825 protected readonly ComposedTypeSpecifier rank;
7826 Expression first_emit;
7827 LocalTemporary first_emit_temp;
7829 protected List<Expression> array_data;
7831 Dictionary<int, int> bounds;
7834 // The number of constants in array initializers
7835 int const_initializers_count;
7836 bool only_constant_initializers;
7838 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7839 : this (requested_base_type, rank, initializers, l)
7841 arguments = new List<Expression> (exprs);
7842 num_arguments = arguments.Count;
7846 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7848 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7850 this.requested_base_type = requested_base_type;
7852 this.initializers = initializers;
7856 num_arguments = rank.Dimension;
7860 // For compiler generated single dimensional arrays only
7862 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7863 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7868 // For expressions like int[] foo = { 1, 2, 3 };
7870 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7871 : this (requested_base_type, null, initializers, initializers.Location)
7875 public bool NoEmptyInterpolation { get; set; }
7877 public ComposedTypeSpecifier Rank {
7883 public FullNamedExpression TypeExpression {
7885 return this.requested_base_type;
7889 public ArrayInitializer Initializers {
7891 return this.initializers;
7895 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7897 if (initializers != null && bounds == null) {
7899 // We use this to store all the data values in the order in which we
7900 // will need to store them in the byte blob later
7902 array_data = new List<Expression> (probe.Count);
7903 bounds = new Dictionary<int, int> ();
7906 if (specified_dims) {
7907 Expression a = arguments [idx];
7912 a = ConvertExpressionToArrayIndex (ec, a);
7918 if (initializers != null) {
7919 Constant c = a as Constant;
7920 if (c == null && a is ArrayIndexCast)
7921 c = ((ArrayIndexCast) a).Child as Constant;
7924 ec.Report.Error (150, a.Location, "A constant value is expected");
7930 value = System.Convert.ToInt32 (c.GetValue ());
7932 ec.Report.Error (150, a.Location, "A constant value is expected");
7936 // TODO: probe.Count does not fit ulong in
7937 if (value != probe.Count) {
7938 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7942 bounds[idx] = value;
7946 if (initializers == null)
7949 for (int i = 0; i < probe.Count; ++i) {
7951 if (o is ArrayInitializer) {
7952 var sub_probe = o as ArrayInitializer;
7953 if (idx + 1 >= dimensions){
7954 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7958 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7959 if (!bounds.ContainsKey(idx + 1))
7960 bounds[idx + 1] = sub_probe.Count;
7962 if (bounds[idx + 1] != sub_probe.Count) {
7963 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7967 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7970 } else if (child_bounds > 1) {
7971 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7973 Expression element = ResolveArrayElement (ec, o);
7974 if (element == null)
7977 // Initializers with the default values can be ignored
7978 Constant c = element as Constant;
7980 if (!c.IsDefaultInitializer (array_element_type)) {
7981 ++const_initializers_count;
7984 only_constant_initializers = false;
7987 array_data.Add (element);
7994 public override bool ContainsEmitWithAwait ()
7996 foreach (var arg in arguments) {
7997 if (arg.ContainsEmitWithAwait ())
8001 return InitializersContainAwait ();
8004 public override Expression CreateExpressionTree (ResolveContext ec)
8008 if (array_data == null) {
8009 args = new Arguments (arguments.Count + 1);
8010 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8011 foreach (Expression a in arguments)
8012 args.Add (new Argument (a.CreateExpressionTree (ec)));
8014 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8017 if (dimensions > 1) {
8018 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8022 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8023 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8024 if (array_data != null) {
8025 for (int i = 0; i < array_data.Count; ++i) {
8026 Expression e = array_data [i];
8027 args.Add (new Argument (e.CreateExpressionTree (ec)));
8031 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8034 void UpdateIndices (ResolveContext rc)
8037 for (var probe = initializers; probe != null;) {
8038 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8040 bounds[i++] = probe.Count;
8042 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8043 probe = (ArrayInitializer) probe[0];
8044 } else if (dimensions > i) {
8052 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8054 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8057 public override void FlowAnalysis (FlowAnalysisContext fc)
8059 foreach (var arg in arguments)
8060 arg.FlowAnalysis (fc);
8062 if (array_data != null) {
8063 foreach (var ad in array_data)
8064 ad.FlowAnalysis (fc);
8068 bool InitializersContainAwait ()
8070 if (array_data == null)
8073 foreach (var expr in array_data) {
8074 if (expr.ContainsEmitWithAwait ())
8081 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8083 element = element.Resolve (ec);
8084 if (element == null)
8087 var te = element as CompoundAssign.TargetExpression;
8089 for (int i = 1; i < initializers.Count; ++i) {
8090 if (initializers [i].ContainsEmitWithAwait ()) {
8091 te.RequiresEmitWithAwait = true;
8096 if (!te.RequiresEmitWithAwait) {
8097 if (first_emit != null)
8098 throw new InternalErrorException ("Can only handle one mutator at a time");
8099 first_emit = element;
8100 element = first_emit_temp = new LocalTemporary (element.Type);
8104 return Convert.ImplicitConversionRequired (
8105 ec, element, array_element_type, loc);
8108 protected bool ResolveInitializers (ResolveContext ec)
8111 only_constant_initializers = true;
8114 if (arguments != null) {
8116 for (int i = 0; i < arguments.Count; ++i) {
8117 res &= CheckIndices (ec, initializers, i, true, dimensions);
8118 if (initializers != null)
8125 arguments = new List<Expression> ();
8127 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8136 // Resolved the type of the array
8138 bool ResolveArrayType (ResolveContext ec)
8143 FullNamedExpression array_type_expr;
8144 if (num_arguments > 0) {
8145 array_type_expr = new ComposedCast (requested_base_type, rank);
8147 array_type_expr = requested_base_type;
8150 type = array_type_expr.ResolveAsType (ec);
8151 if (array_type_expr == null)
8154 var ac = type as ArrayContainer;
8156 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8160 array_element_type = ac.Element;
8161 dimensions = ac.Rank;
8166 protected override Expression DoResolve (ResolveContext ec)
8171 if (!ResolveArrayType (ec))
8175 // validate the initializers and fill in any missing bits
8177 if (!ResolveInitializers (ec))
8180 eclass = ExprClass.Value;
8184 byte [] MakeByteBlob ()
8189 int count = array_data.Count;
8191 TypeSpec element_type = array_element_type;
8192 if (element_type.IsEnum)
8193 element_type = EnumSpec.GetUnderlyingType (element_type);
8195 factor = BuiltinTypeSpec.GetSize (element_type);
8197 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8199 data = new byte [(count * factor + 3) & ~3];
8202 for (int i = 0; i < count; ++i) {
8203 var c = array_data[i] as Constant;
8209 object v = c.GetValue ();
8211 switch (element_type.BuiltinType) {
8212 case BuiltinTypeSpec.Type.Long:
8213 long lval = (long) v;
8215 for (int j = 0; j < factor; ++j) {
8216 data[idx + j] = (byte) (lval & 0xFF);
8220 case BuiltinTypeSpec.Type.ULong:
8221 ulong ulval = (ulong) v;
8223 for (int j = 0; j < factor; ++j) {
8224 data[idx + j] = (byte) (ulval & 0xFF);
8225 ulval = (ulval >> 8);
8228 case BuiltinTypeSpec.Type.Float:
8229 var fval = SingleConverter.SingleToInt32Bits((float) v);
8231 data[idx] = (byte) (fval & 0xff);
8232 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8233 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8234 data[idx + 3] = (byte) (fval >> 24);
8236 case BuiltinTypeSpec.Type.Double:
8237 element = BitConverter.GetBytes ((double) v);
8239 for (int j = 0; j < factor; ++j)
8240 data[idx + j] = element[j];
8242 // FIXME: Handle the ARM float format.
8243 if (!BitConverter.IsLittleEndian)
8244 System.Array.Reverse (data, idx, 8);
8246 case BuiltinTypeSpec.Type.Char:
8247 int chval = (int) ((char) v);
8249 data[idx] = (byte) (chval & 0xff);
8250 data[idx + 1] = (byte) (chval >> 8);
8252 case BuiltinTypeSpec.Type.Short:
8253 int sval = (int) ((short) v);
8255 data[idx] = (byte) (sval & 0xff);
8256 data[idx + 1] = (byte) (sval >> 8);
8258 case BuiltinTypeSpec.Type.UShort:
8259 int usval = (int) ((ushort) v);
8261 data[idx] = (byte) (usval & 0xff);
8262 data[idx + 1] = (byte) (usval >> 8);
8264 case BuiltinTypeSpec.Type.Int:
8267 data[idx] = (byte) (val & 0xff);
8268 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8269 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8270 data[idx + 3] = (byte) (val >> 24);
8272 case BuiltinTypeSpec.Type.UInt:
8273 uint uval = (uint) v;
8275 data[idx] = (byte) (uval & 0xff);
8276 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8277 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8278 data[idx + 3] = (byte) (uval >> 24);
8280 case BuiltinTypeSpec.Type.SByte:
8281 data[idx] = (byte) (sbyte) v;
8283 case BuiltinTypeSpec.Type.Byte:
8284 data[idx] = (byte) v;
8286 case BuiltinTypeSpec.Type.Bool:
8287 data[idx] = (byte) ((bool) v ? 1 : 0);
8289 case BuiltinTypeSpec.Type.Decimal:
8290 int[] bits = Decimal.GetBits ((decimal) v);
8293 // FIXME: For some reason, this doesn't work on the MS runtime.
8294 int[] nbits = new int[4];
8300 for (int j = 0; j < 4; j++) {
8301 data[p++] = (byte) (nbits[j] & 0xff);
8302 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8303 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8304 data[p++] = (byte) (nbits[j] >> 24);
8308 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8317 public override SLE.Expression MakeExpression (BuilderContext ctx)
8320 return base.MakeExpression (ctx);
8322 var initializers = new SLE.Expression [array_data.Count];
8323 for (var i = 0; i < initializers.Length; i++) {
8324 if (array_data [i] == null)
8325 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8327 initializers [i] = array_data [i].MakeExpression (ctx);
8330 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8335 // Emits the initializers for the array
8337 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8339 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8344 // First, the static data
8346 byte [] data = MakeByteBlob ();
8347 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8349 if (stackArray == null) {
8350 ec.Emit (OpCodes.Dup);
8352 stackArray.Emit (ec);
8355 ec.Emit (OpCodes.Ldtoken, fb);
8356 ec.Emit (OpCodes.Call, m);
8361 // Emits pieces of the array that can not be computed at compile
8362 // time (variables and string locations).
8364 // This always expect the top value on the stack to be the array
8366 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8368 int dims = bounds.Count;
8369 var current_pos = new int [dims];
8371 for (int i = 0; i < array_data.Count; i++){
8373 Expression e = array_data [i];
8374 var c = e as Constant;
8376 // Constant can be initialized via StaticInitializer
8377 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8381 if (stackArray != null) {
8382 if (e.ContainsEmitWithAwait ()) {
8383 e = e.EmitToField (ec);
8386 stackArray.EmitLoad (ec);
8388 ec.Emit (OpCodes.Dup);
8391 for (int idx = 0; idx < dims; idx++)
8392 ec.EmitInt (current_pos [idx]);
8395 // If we are dealing with a struct, get the
8396 // address of it, so we can store it.
8398 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8399 ec.Emit (OpCodes.Ldelema, etype);
8403 ec.EmitArrayStore ((ArrayContainer) type);
8409 for (int j = dims - 1; j >= 0; j--){
8411 if (current_pos [j] < bounds [j])
8413 current_pos [j] = 0;
8417 if (stackArray != null)
8418 stackArray.PrepareCleanup (ec);
8421 public override void Emit (EmitContext ec)
8423 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8426 var await_field = EmitToFieldSource (ec);
8427 if (await_field != null)
8428 await_field.Emit (ec);
8431 bool EmitOptimizedEmpty (EmitContext ec)
8433 if (arguments.Count != 1 || dimensions != 1)
8436 var c = arguments [0] as Constant;
8437 if (c == null || !c.IsZeroInteger)
8440 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8441 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8444 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8445 ec.Emit (OpCodes.Call, m);
8449 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8451 if (first_emit != null) {
8452 first_emit.Emit (ec);
8453 first_emit_temp.Store (ec);
8456 StackFieldExpr await_stack_field;
8457 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8458 await_stack_field = ec.GetTemporaryField (type);
8461 await_stack_field = null;
8464 EmitExpressionsList (ec, arguments);
8466 ec.EmitArrayNew ((ArrayContainer) type);
8468 if (initializers == null)
8469 return await_stack_field;
8471 if (await_stack_field != null)
8472 await_stack_field.EmitAssignFromStack (ec);
8476 // Emit static initializer for arrays which contain more than 2 items and
8477 // the static initializer will initialize at least 25% of array values or there
8478 // is more than 10 items to be initialized
8480 // NOTE: const_initializers_count does not contain default constant values.
8482 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8483 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8484 EmitStaticInitializers (ec, await_stack_field);
8486 if (!only_constant_initializers)
8487 EmitDynamicInitializers (ec, false, await_stack_field);
8491 EmitDynamicInitializers (ec, true, await_stack_field);
8494 if (first_emit_temp != null)
8495 first_emit_temp.Release (ec);
8497 return await_stack_field;
8500 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8502 // no multi dimensional or jagged arrays
8503 if (arguments.Count != 1 || array_element_type.IsArray) {
8504 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8508 // No array covariance, except for array -> object
8509 if (type != targetType) {
8510 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8511 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8515 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8516 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8521 // Single dimensional array of 0 size
8522 if (array_data == null) {
8523 IntConstant ic = arguments[0] as IntConstant;
8524 if (ic == null || !ic.IsDefaultValue) {
8525 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8533 enc.Encode (array_data.Count);
8534 foreach (var element in array_data) {
8535 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8539 protected override void CloneTo (CloneContext clonectx, Expression t)
8541 ArrayCreation target = (ArrayCreation) t;
8543 if (requested_base_type != null)
8544 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8546 if (arguments != null){
8547 target.arguments = new List<Expression> (arguments.Count);
8548 foreach (Expression e in arguments)
8549 target.arguments.Add (e.Clone (clonectx));
8552 if (initializers != null)
8553 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8556 public override object Accept (StructuralVisitor visitor)
8558 return visitor.Visit (this);
8563 // Represents an implicitly typed array epxression
8565 class ImplicitlyTypedArrayCreation : ArrayCreation
8567 TypeInferenceContext best_type_inference;
8569 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8570 : base (null, rank, initializers, loc)
8574 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8575 : base (null, initializers, loc)
8579 protected override Expression DoResolve (ResolveContext ec)
8584 dimensions = rank.Dimension;
8586 best_type_inference = new TypeInferenceContext ();
8588 if (!ResolveInitializers (ec))
8591 best_type_inference.FixAllTypes (ec);
8592 array_element_type = best_type_inference.InferredTypeArguments[0];
8593 best_type_inference = null;
8595 if (array_element_type == null ||
8596 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8597 arguments.Count != rank.Dimension) {
8598 ec.Report.Error (826, loc,
8599 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8604 // At this point we found common base type for all initializer elements
8605 // but we have to be sure that all static initializer elements are of
8608 UnifyInitializerElement (ec);
8610 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8611 eclass = ExprClass.Value;
8616 // Converts static initializer only
8618 void UnifyInitializerElement (ResolveContext ec)
8620 for (int i = 0; i < array_data.Count; ++i) {
8621 Expression e = array_data[i];
8623 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8627 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8629 element = element.Resolve (ec);
8630 if (element != null)
8631 best_type_inference.AddCommonTypeBound (element.Type);
8637 sealed class CompilerGeneratedThis : This
8639 public CompilerGeneratedThis (TypeSpec type, Location loc)
8645 protected override Expression DoResolve (ResolveContext rc)
8647 eclass = ExprClass.Variable;
8649 var block = rc.CurrentBlock;
8650 if (block != null) {
8651 var top = block.ParametersBlock.TopBlock;
8652 if (top.ThisVariable != null)
8653 variable_info = top.ThisVariable.VariableInfo;
8660 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8662 return DoResolve (rc);
8665 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8672 /// Represents the `this' construct
8675 public class This : VariableReference
8677 sealed class ThisVariable : ILocalVariable
8679 public static readonly ILocalVariable Instance = new ThisVariable ();
8681 public void Emit (EmitContext ec)
8686 public void EmitAssign (EmitContext ec)
8688 throw new InvalidOperationException ();
8691 public void EmitAddressOf (EmitContext ec)
8697 protected VariableInfo variable_info;
8699 public This (Location loc)
8706 public override string Name {
8707 get { return "this"; }
8710 public override bool IsLockedByStatement {
8718 public override bool IsRef {
8719 get { return type.IsStruct; }
8722 public override bool IsSideEffectFree {
8728 protected override ILocalVariable Variable {
8729 get { return ThisVariable.Instance; }
8732 public override VariableInfo VariableInfo {
8733 get { return variable_info; }
8736 public override bool IsFixed {
8737 get { return false; }
8742 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8745 // It's null for all cases when we don't need to check `this'
8746 // definitive assignment
8748 if (variable_info == null)
8751 if (fc.IsDefinitelyAssigned (variable_info))
8754 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8757 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8759 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8760 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8761 } else if (ec.CurrentAnonymousMethod != null) {
8762 ec.Report.Error (1673, loc,
8763 "Anonymous methods inside structs cannot access instance members of `this'. " +
8764 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8766 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8770 public override void FlowAnalysis (FlowAnalysisContext fc)
8772 CheckStructThisDefiniteAssignment (fc);
8775 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8780 AnonymousMethodStorey storey = ae.Storey;
8781 return storey != null ? storey.HoistedThis : null;
8784 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8786 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8789 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8792 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8798 public virtual void ResolveBase (ResolveContext ec)
8800 eclass = ExprClass.Variable;
8801 type = ec.CurrentType;
8803 if (!IsThisAvailable (ec, false)) {
8804 Error_ThisNotAvailable (ec);
8808 var block = ec.CurrentBlock;
8809 if (block != null) {
8810 var top = block.ParametersBlock.TopBlock;
8811 if (top.ThisVariable != null)
8812 variable_info = top.ThisVariable.VariableInfo;
8814 AnonymousExpression am = ec.CurrentAnonymousMethod;
8815 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8817 // Hoisted this is almost like hoisted variable but not exactly. When
8818 // there is no variable hoisted we can simply emit an instance method
8819 // without lifting this into a storey. Unfotunatelly this complicates
8820 // things in other cases because we don't know where this will be hoisted
8821 // until top-level block is fully resolved
8823 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8824 am.SetHasThisAccess ();
8829 protected override Expression DoResolve (ResolveContext ec)
8835 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8837 if (eclass == ExprClass.Unresolved)
8841 if (right_side == EmptyExpression.UnaryAddress)
8842 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8843 else if (right_side == EmptyExpression.OutAccess)
8844 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8846 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8852 public override int GetHashCode()
8854 throw new NotImplementedException ();
8857 public override bool Equals (object obj)
8859 This t = obj as This;
8866 protected override void CloneTo (CloneContext clonectx, Expression t)
8871 public override void SetHasAddressTaken ()
8876 public override object Accept (StructuralVisitor visitor)
8878 return visitor.Visit (this);
8883 /// Represents the `__arglist' construct
8885 public class ArglistAccess : Expression
8887 public ArglistAccess (Location loc)
8892 protected override void CloneTo (CloneContext clonectx, Expression target)
8897 public override bool ContainsEmitWithAwait ()
8902 public override Expression CreateExpressionTree (ResolveContext ec)
8904 throw new NotSupportedException ("ET");
8907 protected override Expression DoResolve (ResolveContext ec)
8909 eclass = ExprClass.Variable;
8910 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8912 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8913 ec.Report.Error (190, loc,
8914 "The __arglist construct is valid only within a variable argument method");
8920 public override void Emit (EmitContext ec)
8922 ec.Emit (OpCodes.Arglist);
8925 public override object Accept (StructuralVisitor visitor)
8927 return visitor.Visit (this);
8932 /// Represents the `__arglist (....)' construct
8934 public class Arglist : Expression
8936 Arguments arguments;
8938 public Arglist (Location loc)
8943 public Arglist (Arguments args, Location l)
8949 public Arguments Arguments {
8955 public MetaType[] ArgumentTypes {
8957 if (arguments == null)
8958 return MetaType.EmptyTypes;
8960 var retval = new MetaType[arguments.Count];
8961 for (int i = 0; i < retval.Length; i++)
8962 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8968 public override bool ContainsEmitWithAwait ()
8970 throw new NotImplementedException ();
8973 public override Expression CreateExpressionTree (ResolveContext ec)
8975 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8979 protected override Expression DoResolve (ResolveContext ec)
8981 eclass = ExprClass.Variable;
8982 type = InternalType.Arglist;
8983 if (arguments != null) {
8984 bool dynamic; // Can be ignored as there is always only 1 overload
8985 arguments.Resolve (ec, out dynamic);
8991 public override void Emit (EmitContext ec)
8993 if (arguments != null)
8994 arguments.Emit (ec);
8997 protected override void CloneTo (CloneContext clonectx, Expression t)
8999 Arglist target = (Arglist) t;
9001 if (arguments != null)
9002 target.arguments = arguments.Clone (clonectx);
9005 public override object Accept (StructuralVisitor visitor)
9007 return visitor.Visit (this);
9011 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9013 FullNamedExpression texpr;
9015 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9022 public FullNamedExpression TypeExpression {
9028 public override bool ContainsEmitWithAwait ()
9033 public void AddressOf (EmitContext ec, AddressOp mode)
9036 ec.Emit (OpCodes.Refanyval, type);
9039 protected override Expression DoResolve (ResolveContext rc)
9041 expr = expr.Resolve (rc);
9042 type = texpr.ResolveAsType (rc);
9043 if (expr == null || type == null)
9046 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9047 eclass = ExprClass.Variable;
9051 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9053 return DoResolve (rc);
9056 public override void Emit (EmitContext ec)
9059 ec.Emit (OpCodes.Refanyval, type);
9060 ec.EmitLoadFromPtr (type);
9063 public void Emit (EmitContext ec, bool leave_copy)
9065 throw new NotImplementedException ();
9068 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9071 ec.Emit (OpCodes.Refanyval, type);
9074 LocalTemporary temporary = null;
9076 ec.Emit (OpCodes.Dup);
9077 temporary = new LocalTemporary (source.Type);
9078 temporary.Store (ec);
9081 ec.EmitStoreFromPtr (type);
9083 if (temporary != null) {
9084 temporary.Emit (ec);
9085 temporary.Release (ec);
9089 public override object Accept (StructuralVisitor visitor)
9091 return visitor.Visit (this);
9095 public class RefTypeExpr : ShimExpression
9097 public RefTypeExpr (Expression expr, Location loc)
9103 protected override Expression DoResolve (ResolveContext rc)
9105 expr = expr.Resolve (rc);
9109 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9113 type = rc.BuiltinTypes.Type;
9114 eclass = ExprClass.Value;
9118 public override void Emit (EmitContext ec)
9121 ec.Emit (OpCodes.Refanytype);
9122 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9124 ec.Emit (OpCodes.Call, m);
9127 public override object Accept (StructuralVisitor visitor)
9129 return visitor.Visit (this);
9133 public class MakeRefExpr : ShimExpression
9135 public MakeRefExpr (Expression expr, Location loc)
9141 public override bool ContainsEmitWithAwait ()
9143 throw new NotImplementedException ();
9146 protected override Expression DoResolve (ResolveContext rc)
9148 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9149 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9150 eclass = ExprClass.Value;
9154 public override void Emit (EmitContext ec)
9156 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9157 ec.Emit (OpCodes.Mkrefany, expr.Type);
9160 public override object Accept (StructuralVisitor visitor)
9162 return visitor.Visit (this);
9167 /// Implements the typeof operator
9169 public class TypeOf : Expression {
9170 FullNamedExpression QueriedType;
9173 public TypeOf (FullNamedExpression queried_type, Location l)
9175 QueriedType = queried_type;
9180 // Use this constructor for any compiler generated typeof expression
9182 public TypeOf (TypeSpec type, Location loc)
9184 this.typearg = type;
9190 public override bool IsSideEffectFree {
9196 public TypeSpec TypeArgument {
9202 public FullNamedExpression TypeExpression {
9211 protected override void CloneTo (CloneContext clonectx, Expression t)
9213 TypeOf target = (TypeOf) t;
9214 if (QueriedType != null)
9215 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9218 public override bool ContainsEmitWithAwait ()
9223 public override Expression CreateExpressionTree (ResolveContext ec)
9225 Arguments args = new Arguments (2);
9226 args.Add (new Argument (this));
9227 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9228 return CreateExpressionFactoryCall (ec, "Constant", args);
9231 protected override Expression DoResolve (ResolveContext ec)
9233 if (eclass != ExprClass.Unresolved)
9236 if (typearg == null) {
9238 // Pointer types are allowed without explicit unsafe, they are just tokens
9240 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9241 typearg = QueriedType.ResolveAsType (ec, true);
9244 if (typearg == null)
9247 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9248 ec.Report.Error (1962, QueriedType.Location,
9249 "The typeof operator cannot be used on the dynamic type");
9253 type = ec.BuiltinTypes.Type;
9255 // Even though what is returned is a type object, it's treated as a value by the compiler.
9256 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9257 eclass = ExprClass.Value;
9261 static bool ContainsDynamicType (TypeSpec type)
9263 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9266 var element_container = type as ElementTypeSpec;
9267 if (element_container != null)
9268 return ContainsDynamicType (element_container.Element);
9270 foreach (var t in type.TypeArguments) {
9271 if (ContainsDynamicType (t)) {
9279 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9281 // Target type is not System.Type therefore must be object
9282 // and we need to use different encoding sequence
9283 if (targetType != type)
9286 if (typearg is InflatedTypeSpec) {
9289 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9290 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9291 typearg.GetSignatureForError ());
9295 gt = gt.DeclaringType;
9296 } while (gt != null);
9299 if (ContainsDynamicType (typearg)) {
9300 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9304 enc.EncodeTypeName (typearg);
9307 public override void Emit (EmitContext ec)
9309 ec.Emit (OpCodes.Ldtoken, typearg);
9310 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9312 ec.Emit (OpCodes.Call, m);
9315 public override object Accept (StructuralVisitor visitor)
9317 return visitor.Visit (this);
9321 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9323 public TypeOfMethod (MethodSpec method, Location loc)
9324 : base (method, loc)
9328 protected override Expression DoResolve (ResolveContext ec)
9330 if (member.IsConstructor) {
9331 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9333 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9339 return base.DoResolve (ec);
9342 public override void Emit (EmitContext ec)
9344 ec.Emit (OpCodes.Ldtoken, member);
9347 ec.Emit (OpCodes.Castclass, type);
9350 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9352 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9355 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9357 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9361 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9363 protected readonly T member;
9365 protected TypeOfMember (T member, Location loc)
9367 this.member = member;
9371 public override bool IsSideEffectFree {
9377 public override bool ContainsEmitWithAwait ()
9382 public override Expression CreateExpressionTree (ResolveContext ec)
9384 Arguments args = new Arguments (2);
9385 args.Add (new Argument (this));
9386 args.Add (new Argument (new TypeOf (type, loc)));
9387 return CreateExpressionFactoryCall (ec, "Constant", args);
9390 protected override Expression DoResolve (ResolveContext ec)
9392 eclass = ExprClass.Value;
9396 public override void Emit (EmitContext ec)
9398 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9399 PredefinedMember<MethodSpec> p;
9401 p = GetTypeFromHandleGeneric (ec);
9402 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9404 p = GetTypeFromHandle (ec);
9407 var mi = p.Resolve (loc);
9409 ec.Emit (OpCodes.Call, mi);
9412 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9413 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9416 sealed class TypeOfField : TypeOfMember<FieldSpec>
9418 public TypeOfField (FieldSpec field, Location loc)
9423 protected override Expression DoResolve (ResolveContext ec)
9425 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9429 return base.DoResolve (ec);
9432 public override void Emit (EmitContext ec)
9434 ec.Emit (OpCodes.Ldtoken, member);
9438 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9440 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9443 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9445 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9450 /// Implements the sizeof expression
9452 public class SizeOf : Expression {
9453 readonly Expression texpr;
9454 TypeSpec type_queried;
9456 public SizeOf (Expression queried_type, Location l)
9458 this.texpr = queried_type;
9462 public override bool IsSideEffectFree {
9468 public Expression TypeExpression {
9474 public override bool ContainsEmitWithAwait ()
9479 public override Expression CreateExpressionTree (ResolveContext ec)
9481 Error_PointerInsideExpressionTree (ec);
9485 protected override Expression DoResolve (ResolveContext ec)
9487 type_queried = texpr.ResolveAsType (ec);
9488 if (type_queried == null)
9491 if (type_queried.IsEnum)
9492 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9494 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9496 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9499 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9504 ec.Report.Error (233, loc,
9505 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9506 type_queried.GetSignatureForError ());
9509 type = ec.BuiltinTypes.Int;
9510 eclass = ExprClass.Value;
9514 public override void Emit (EmitContext ec)
9516 ec.Emit (OpCodes.Sizeof, type_queried);
9519 protected override void CloneTo (CloneContext clonectx, Expression t)
9523 public override object Accept (StructuralVisitor visitor)
9525 return visitor.Visit (this);
9530 /// Implements the qualified-alias-member (::) expression.
9532 public class QualifiedAliasMember : MemberAccess
9534 readonly string alias;
9535 public static readonly string GlobalAlias = "global";
9537 public QualifiedAliasMember (string alias, string identifier, Location l)
9538 : base (null, identifier, l)
9543 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9544 : base (null, identifier, targs, l)
9549 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9550 : base (null, identifier, arity, l)
9555 public string Alias {
9561 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9563 if (alias == GlobalAlias)
9564 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9566 int errors = mc.Module.Compiler.Report.Errors;
9567 var expr = mc.LookupNamespaceAlias (alias);
9569 if (errors == mc.Module.Compiler.Report.Errors)
9570 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9578 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9580 expr = CreateExpressionFromAlias (mc);
9584 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9587 protected override Expression DoResolve (ResolveContext rc)
9589 return ResolveAsTypeOrNamespace (rc, false);
9592 public override string GetSignatureForError ()
9595 if (targs != null) {
9596 name = Name + "<" + targs.GetSignatureForError () + ">";
9599 return alias + "::" + name;
9602 public override bool HasConditionalAccess ()
9607 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9609 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9610 rc.Module.Compiler.Report.Error (687, loc,
9611 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9612 GetSignatureForError ());
9617 return DoResolve (rc);
9620 protected override void CloneTo (CloneContext clonectx, Expression t)
9625 public override object Accept (StructuralVisitor visitor)
9627 return visitor.Visit (this);
9632 /// Implements the member access expression
9634 public class MemberAccess : ATypeNameExpression
9636 protected Expression expr;
9638 public MemberAccess (Expression expr, string id)
9639 : base (id, expr.Location)
9644 public MemberAccess (Expression expr, string identifier, Location loc)
9645 : base (identifier, loc)
9650 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9651 : base (identifier, args, loc)
9656 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9657 : base (identifier, arity, loc)
9662 public Expression LeftExpression {
9668 public override Location StartLocation {
9670 return expr == null ? loc : expr.StartLocation;
9674 protected override Expression DoResolve (ResolveContext rc)
9676 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9678 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9683 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9685 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9687 if (e is TypeExpr) {
9688 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9693 e = e.ResolveLValue (rc, rhs);
9698 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9700 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9701 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9703 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9706 public override bool HasConditionalAccess ()
9708 return LeftExpression.HasConditionalAccess ();
9711 public static bool IsValidDotExpression (TypeSpec type)
9713 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9714 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9716 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9719 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9721 var sn = expr as SimpleName;
9722 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9725 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9728 // Resolve expression which does have type set as we need expression type
9729 // with disable flow analysis as we don't know whether left side expression
9730 // is used as variable or type
9732 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9733 expr = expr.Resolve (rc);
9734 } else if (expr is TypeParameterExpr) {
9735 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9739 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9740 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9741 expr = expr.Resolve (rc, flags);
9744 expr = expr.Resolve (rc, flags);
9751 var ns = expr as NamespaceExpression;
9753 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9755 if (retval == null) {
9756 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9761 if (HasTypeArguments)
9762 return new GenericTypeExpr (retval.Type, targs, loc);
9764 targs.Resolve (rc, false);
9770 var cma = this as ConditionalMemberAccess;
9773 TypeSpec expr_type = expr.Type;
9774 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9775 me = expr as MemberExpr;
9777 me.ResolveInstanceExpression (rc, null);
9779 Arguments args = new Arguments (1);
9780 args.Add (new Argument (expr));
9783 return new DynamicConditionalMemberBinder (Name, args, loc);
9785 return new DynamicMemberBinder (Name, args, loc);
9789 if (!IsNullPropagatingValid (expr.Type)) {
9790 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9794 if (expr_type.IsNullableType) {
9795 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9796 expr_type = expr.Type;
9800 if (!IsValidDotExpression (expr_type)) {
9801 Error_OperatorCannotBeApplied (rc, expr_type);
9805 var lookup_arity = Arity;
9806 bool errorMode = false;
9807 Expression member_lookup;
9809 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9810 if (member_lookup == null) {
9812 // Try to look for extension method when member lookup failed
9814 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9815 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9816 if (methods != null) {
9817 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9818 if (HasTypeArguments) {
9819 if (!targs.Resolve (rc, false))
9822 emg.SetTypeArguments (rc, targs);
9826 emg.ConditionalAccess = true;
9828 // TODO: it should really skip the checks bellow
9829 return emg.Resolve (rc);
9835 if (member_lookup == null) {
9836 var dep = expr_type.GetMissingDependencies ();
9838 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9839 } else if (expr is TypeExpr) {
9840 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9842 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9848 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9849 // Leave it to overload resolution to report correct error
9850 } else if (!(member_lookup is TypeExpr)) {
9851 // TODO: rc.SymbolRelatedToPreviousError
9852 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9857 if (member_lookup != null)
9861 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9865 TypeExpr texpr = member_lookup as TypeExpr;
9866 if (texpr != null) {
9867 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9868 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9869 Name, texpr.GetSignatureForError ());
9872 if (!texpr.Type.IsAccessible (rc)) {
9873 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9874 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9878 if (HasTypeArguments) {
9879 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9882 return member_lookup;
9885 me = member_lookup as MemberExpr;
9887 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9892 me.ConditionalAccess = true;
9895 me = me.ResolveMemberAccess (rc, expr, sn);
9898 if (!targs.Resolve (rc, false))
9901 me.SetTypeArguments (rc, targs);
9907 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9909 FullNamedExpression fexpr = expr as FullNamedExpression;
9910 if (fexpr == null) {
9911 expr.ResolveAsType (rc);
9915 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9917 if (expr_resolved == null)
9920 var ns = expr_resolved as NamespaceExpression;
9922 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9924 if (retval == null) {
9925 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9926 } else if (Arity > 0) {
9927 if (HasTypeArguments) {
9928 retval = new GenericTypeExpr (retval.Type, targs, loc);
9929 if (retval.ResolveAsType (rc) == null)
9932 targs.Resolve (rc, allowUnboundTypeArguments);
9934 retval = new GenericOpenTypeExpr (retval.Type, loc);
9941 var tnew_expr = expr_resolved.ResolveAsType (rc);
9942 if (tnew_expr == null)
9945 TypeSpec expr_type = tnew_expr;
9946 if (TypeManager.IsGenericParameter (expr_type)) {
9947 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9948 tnew_expr.GetSignatureForError ());
9952 var qam = this as QualifiedAliasMember;
9954 rc.Module.Compiler.Report.Error (431, loc,
9955 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9960 TypeSpec nested = null;
9961 while (expr_type != null) {
9962 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9963 if (nested == null) {
9964 if (expr_type == tnew_expr) {
9965 Error_IdentifierNotFound (rc, expr_type);
9969 expr_type = tnew_expr;
9970 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9971 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9975 if (nested.IsAccessible (rc))
9979 // Keep looking after inaccessible candidate but only if
9980 // we are not in same context as the definition itself
9982 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9985 expr_type = expr_type.BaseType;
9990 if (HasTypeArguments) {
9991 texpr = new GenericTypeExpr (nested, targs, loc);
9993 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9995 texpr = new GenericOpenTypeExpr (nested, loc);
9997 } else if (expr_resolved is GenericOpenTypeExpr) {
9998 texpr = new GenericOpenTypeExpr (nested, loc);
10000 texpr = new TypeExpression (nested, loc);
10003 if (texpr.ResolveAsType (rc) == null)
10009 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10011 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
10013 if (nested != null) {
10014 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10018 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10019 if (any_other_member != null) {
10020 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10024 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10025 Name, expr_type.GetSignatureForError ());
10028 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10030 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10033 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10035 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10036 ec.Report.SymbolRelatedToPreviousError (type);
10038 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10040 // a using directive or an assembly reference
10041 if (cand != null) {
10042 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10044 missing = "an assembly reference";
10047 ec.Report.Error (1061, loc,
10048 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10049 type.GetSignatureForError (), name, missing);
10053 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10056 public override string GetSignatureForError ()
10058 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10061 protected override void CloneTo (CloneContext clonectx, Expression t)
10063 MemberAccess target = (MemberAccess) t;
10065 target.expr = expr.Clone (clonectx);
10068 public override object Accept (StructuralVisitor visitor)
10070 return visitor.Visit (this);
10074 public class ConditionalMemberAccess : MemberAccess
10076 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10077 : base (expr, identifier, args, loc)
10081 public override bool HasConditionalAccess ()
10088 /// Implements checked expressions
10090 public class CheckedExpr : Expression {
10092 public Expression Expr;
10094 public CheckedExpr (Expression e, Location l)
10100 public override bool ContainsEmitWithAwait ()
10102 return Expr.ContainsEmitWithAwait ();
10105 public override Expression CreateExpressionTree (ResolveContext ec)
10107 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10108 return Expr.CreateExpressionTree (ec);
10111 protected override Expression DoResolve (ResolveContext ec)
10113 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10114 Expr = Expr.Resolve (ec);
10119 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10122 eclass = Expr.eclass;
10127 public override void Emit (EmitContext ec)
10129 using (ec.With (EmitContext.Options.CheckedScope, true))
10133 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10135 using (ec.With (EmitContext.Options.CheckedScope, true))
10136 Expr.EmitBranchable (ec, target, on_true);
10139 public override void FlowAnalysis (FlowAnalysisContext fc)
10141 Expr.FlowAnalysis (fc);
10144 public override SLE.Expression MakeExpression (BuilderContext ctx)
10146 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10147 return Expr.MakeExpression (ctx);
10151 protected override void CloneTo (CloneContext clonectx, Expression t)
10153 CheckedExpr target = (CheckedExpr) t;
10155 target.Expr = Expr.Clone (clonectx);
10158 public override object Accept (StructuralVisitor visitor)
10160 return visitor.Visit (this);
10165 /// Implements the unchecked expression
10167 public class UnCheckedExpr : Expression {
10169 public Expression Expr;
10171 public UnCheckedExpr (Expression e, Location l)
10177 public override bool ContainsEmitWithAwait ()
10179 return Expr.ContainsEmitWithAwait ();
10182 public override Expression CreateExpressionTree (ResolveContext ec)
10184 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10185 return Expr.CreateExpressionTree (ec);
10188 protected override Expression DoResolve (ResolveContext ec)
10190 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10191 Expr = Expr.Resolve (ec);
10196 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10199 eclass = Expr.eclass;
10204 public override void Emit (EmitContext ec)
10206 using (ec.With (EmitContext.Options.CheckedScope, false))
10210 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10212 using (ec.With (EmitContext.Options.CheckedScope, false))
10213 Expr.EmitBranchable (ec, target, on_true);
10216 public override void FlowAnalysis (FlowAnalysisContext fc)
10218 Expr.FlowAnalysis (fc);
10221 protected override void CloneTo (CloneContext clonectx, Expression t)
10223 UnCheckedExpr target = (UnCheckedExpr) t;
10225 target.Expr = Expr.Clone (clonectx);
10228 public override object Accept (StructuralVisitor visitor)
10230 return visitor.Visit (this);
10235 /// An Element Access expression.
10237 /// During semantic analysis these are transformed into
10238 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10240 public class ElementAccess : Expression
10242 public Arguments Arguments;
10243 public Expression Expr;
10244 bool conditional_access_receiver;
10246 public ElementAccess (Expression e, Arguments args, Location loc)
10250 this.Arguments = args;
10253 public bool ConditionalAccess { get; set; }
10255 public override Location StartLocation {
10257 return Expr.StartLocation;
10261 public override bool ContainsEmitWithAwait ()
10263 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10267 // We perform some simple tests, and then to "split" the emit and store
10268 // code we create an instance of a different class, and return that.
10270 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10272 if (conditionalAccessReceiver)
10273 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10275 Expr = Expr.Resolve (ec);
10277 if (conditionalAccessReceiver)
10278 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10285 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10286 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10290 if (type.IsArray) {
10291 var aa = new ArrayAccess (this, loc) {
10292 ConditionalAccess = ConditionalAccess,
10295 if (conditionalAccessReceiver)
10296 aa.SetConditionalAccessReceiver ();
10301 if (type.IsPointer)
10302 return Expr.MakePointerAccess (ec, type, Arguments);
10304 FieldExpr fe = Expr as FieldExpr;
10306 var ff = fe.Spec as FixedFieldSpec;
10308 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10312 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10313 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10314 var indexer = new IndexerExpr (indexers, type, this) {
10315 ConditionalAccess = ConditionalAccess
10318 if (conditionalAccessReceiver)
10319 indexer.SetConditionalAccessReceiver ();
10324 Error_CannotApplyIndexing (ec, type, loc);
10329 public override Expression CreateExpressionTree (ResolveContext ec)
10331 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10332 Expr.CreateExpressionTree (ec));
10334 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10337 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10339 if (type != InternalType.ErrorType) {
10340 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10341 type.GetSignatureForError ());
10345 public override bool HasConditionalAccess ()
10347 return ConditionalAccess || Expr.HasConditionalAccess ();
10350 void ResolveConditionalAccessReceiver (ResolveContext rc)
10352 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10353 conditional_access_receiver = true;
10357 protected override Expression DoResolve (ResolveContext rc)
10359 ResolveConditionalAccessReceiver (rc);
10361 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10365 return expr.Resolve (rc);
10368 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10370 var res = CreateAccessExpression (ec, false);
10374 return res.ResolveLValue (ec, rhs);
10377 public override void Emit (EmitContext ec)
10379 throw new Exception ("Should never be reached");
10382 public override void FlowAnalysis (FlowAnalysisContext fc)
10384 Expr.FlowAnalysis (fc);
10386 Arguments.FlowAnalysis (fc);
10389 public override string GetSignatureForError ()
10391 return Expr.GetSignatureForError ();
10394 protected override void CloneTo (CloneContext clonectx, Expression t)
10396 ElementAccess target = (ElementAccess) t;
10398 target.Expr = Expr.Clone (clonectx);
10399 if (Arguments != null)
10400 target.Arguments = Arguments.Clone (clonectx);
10403 public override object Accept (StructuralVisitor visitor)
10405 return visitor.Visit (this);
10410 /// Implements array access
10412 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10414 // Points to our "data" repository
10418 LocalTemporary temp;
10420 bool? has_await_args;
10421 bool conditional_access_receiver;
10423 public ArrayAccess (ElementAccess ea_data, Location l)
10429 public bool ConditionalAccess { get; set; }
10431 public void AddressOf (EmitContext ec, AddressOp mode)
10433 var ac = (ArrayContainer) ea.Expr.Type;
10435 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10436 LoadInstanceAndArguments (ec, false, true);
10439 LoadInstanceAndArguments (ec, false, false);
10441 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10442 ec.Emit (OpCodes.Readonly);
10444 ec.EmitArrayAddress (ac);
10447 public override Expression CreateExpressionTree (ResolveContext ec)
10449 if (ConditionalAccess)
10450 Error_NullShortCircuitInsideExpressionTree (ec);
10452 return ea.CreateExpressionTree (ec);
10455 public override bool ContainsEmitWithAwait ()
10457 return ea.ContainsEmitWithAwait ();
10460 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10462 if (HasConditionalAccess ())
10463 Error_NullPropagatingLValue (ec);
10465 return DoResolve (ec);
10468 protected override Expression DoResolve (ResolveContext ec)
10470 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10472 ea.Arguments.Resolve (ec, out dynamic);
10474 var ac = ea.Expr.Type as ArrayContainer;
10475 int rank = ea.Arguments.Count;
10476 if (ac.Rank != rank) {
10477 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10478 rank.ToString (), ac.Rank.ToString ());
10483 if (type.IsPointer && !ec.IsUnsafe) {
10484 UnsafeError (ec, ea.Location);
10487 if (conditional_access_receiver)
10488 type = LiftMemberType (ec, type);
10490 foreach (Argument a in ea.Arguments) {
10491 var na = a as NamedArgument;
10493 ElementAccess.Error_NamedArgument (na, ec.Report);
10495 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10498 eclass = ExprClass.Variable;
10503 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10505 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10508 public override void FlowAnalysis (FlowAnalysisContext fc)
10510 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10512 ea.FlowAnalysis (fc);
10514 if (conditional_access_receiver)
10515 fc.DefiniteAssignment = da;
10518 public override bool HasConditionalAccess ()
10520 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10524 // Load the array arguments into the stack.
10526 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10528 if (prepareAwait) {
10529 ea.Expr = ea.Expr.EmitToField (ec);
10531 var ie = new InstanceEmitter (ea.Expr, false);
10532 ie.Emit (ec, ConditionalAccess);
10534 if (duplicateArguments) {
10535 ec.Emit (OpCodes.Dup);
10537 var copy = new LocalTemporary (ea.Expr.Type);
10543 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10544 if (dup_args != null)
10545 ea.Arguments = dup_args;
10548 public void Emit (EmitContext ec, bool leave_copy)
10551 ec.EmitLoadFromPtr (type);
10553 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10554 LoadInstanceAndArguments (ec, false, true);
10557 if (conditional_access_receiver)
10558 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10560 var ac = (ArrayContainer) ea.Expr.Type;
10561 LoadInstanceAndArguments (ec, false, false);
10562 ec.EmitArrayLoad (ac);
10564 if (conditional_access_receiver)
10565 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10569 ec.Emit (OpCodes.Dup);
10570 temp = new LocalTemporary (this.type);
10575 public override void Emit (EmitContext ec)
10580 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10582 var ac = (ArrayContainer) ea.Expr.Type;
10583 TypeSpec t = source.Type;
10585 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10588 // When we are dealing with a struct, get the address of it to avoid value copy
10589 // Same cannot be done for reference type because array covariance and the
10590 // check in ldelema requires to specify the type of array element stored at the index
10592 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10593 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10595 if (has_await_args.Value) {
10596 if (source.ContainsEmitWithAwait ()) {
10597 source = source.EmitToField (ec);
10598 isCompound = false;
10602 LoadInstanceAndArguments (ec, isCompound, false);
10607 ec.EmitArrayAddress (ac);
10610 ec.Emit (OpCodes.Dup);
10614 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10616 if (has_await_args.Value) {
10617 if (source.ContainsEmitWithAwait ())
10618 source = source.EmitToField (ec);
10620 LoadInstanceAndArguments (ec, false, false);
10627 var lt = ea.Expr as LocalTemporary;
10633 ec.Emit (OpCodes.Dup);
10634 temp = new LocalTemporary (this.type);
10639 ec.EmitStoreFromPtr (t);
10641 ec.EmitArrayStore (ac);
10644 if (temp != null) {
10650 public override Expression EmitToField (EmitContext ec)
10653 // Have to be specialized for arrays to get access to
10654 // underlying element. Instead of another result copy we
10655 // need direct access to element
10659 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10661 ea.Expr = ea.Expr.EmitToField (ec);
10662 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10666 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10668 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10671 public override SLE.Expression MakeExpression (BuilderContext ctx)
10673 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10676 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10678 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10679 return Arguments.MakeExpression (ea.Arguments, ctx);
10683 public void SetConditionalAccessReceiver ()
10685 conditional_access_receiver = true;
10690 // Indexer access expression
10692 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10694 IList<MemberSpec> indexers;
10695 Arguments arguments;
10696 TypeSpec queried_type;
10698 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10699 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10703 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10706 this.indexers = indexers;
10707 this.queried_type = queriedType;
10708 this.InstanceExpression = instance;
10709 this.arguments = args;
10714 protected override Arguments Arguments {
10723 protected override TypeSpec DeclaringType {
10725 return best_candidate.DeclaringType;
10729 public override bool IsInstance {
10735 public override bool IsStatic {
10741 public override string KindName {
10742 get { return "indexer"; }
10745 public override string Name {
10753 public override bool ContainsEmitWithAwait ()
10755 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10758 public override Expression CreateExpressionTree (ResolveContext ec)
10760 if (ConditionalAccess) {
10761 Error_NullShortCircuitInsideExpressionTree (ec);
10764 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10765 InstanceExpression.CreateExpressionTree (ec),
10766 new TypeOfMethod (Getter, loc));
10768 return CreateExpressionFactoryCall (ec, "Call", args);
10771 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10773 LocalTemporary await_source_arg = null;
10776 emitting_compound_assignment = true;
10777 if (source is DynamicExpressionStatement) {
10782 emitting_compound_assignment = false;
10784 if (has_await_arguments) {
10785 await_source_arg = new LocalTemporary (Type);
10786 await_source_arg.Store (ec);
10788 arguments.Add (new Argument (await_source_arg));
10791 temp = await_source_arg;
10794 has_await_arguments = false;
10799 ec.Emit (OpCodes.Dup);
10800 temp = new LocalTemporary (Type);
10806 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10807 source = source.EmitToField (ec);
10809 temp = new LocalTemporary (Type);
10816 arguments.Add (new Argument (source));
10819 var call = new CallEmitter ();
10820 call.InstanceExpression = InstanceExpression;
10821 if (arguments == null)
10822 call.InstanceExpressionOnStack = true;
10824 call.Emit (ec, Setter, arguments, loc);
10826 if (temp != null) {
10829 } else if (leave_copy) {
10833 if (await_source_arg != null) {
10834 await_source_arg.Release (ec);
10838 public override void FlowAnalysis (FlowAnalysisContext fc)
10840 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10842 base.FlowAnalysis (fc);
10843 arguments.FlowAnalysis (fc);
10845 if (conditional_access_receiver)
10846 fc.DefiniteAssignment = da;
10849 public override string GetSignatureForError ()
10851 return best_candidate.GetSignatureForError ();
10854 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10857 throw new NotSupportedException ();
10859 var value = new[] { source.MakeExpression (ctx) };
10860 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10861 return SLE.Expression.Block (
10862 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10867 public override SLE.Expression MakeExpression (BuilderContext ctx)
10870 return base.MakeExpression (ctx);
10872 var args = Arguments.MakeExpression (arguments, ctx);
10873 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10877 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10879 if (best_candidate != null)
10882 eclass = ExprClass.IndexerAccess;
10885 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10886 arguments.Resolve (rc, out dynamic);
10889 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10892 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10893 res.BaseMembersProvider = this;
10894 res.InstanceQualifier = this;
10896 // TODO: Do I need 2 argument sets?
10897 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10898 if (best_candidate != null)
10899 type = res.BestCandidateReturnType;
10900 else if (!res.BestCandidateIsDynamic)
10905 // It has dynamic arguments
10908 Arguments args = new Arguments (arguments.Count + 1);
10910 rc.Report.Error (1972, loc,
10911 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10913 args.Add (new Argument (InstanceExpression));
10915 args.AddRange (arguments);
10917 best_candidate = null;
10918 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10922 // Try to avoid resolving left expression again
10924 if (right_side != null)
10925 ResolveInstanceExpression (rc, right_side);
10930 protected override void CloneTo (CloneContext clonectx, Expression t)
10932 IndexerExpr target = (IndexerExpr) t;
10934 if (arguments != null)
10935 target.arguments = arguments.Clone (clonectx);
10938 public void SetConditionalAccessReceiver ()
10940 conditional_access_receiver = true;
10943 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10945 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10948 #region IBaseMembersProvider Members
10950 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10952 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10955 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10957 if (queried_type == member.DeclaringType)
10960 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10961 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10964 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10973 // A base access expression
10975 public class BaseThis : This
10977 public BaseThis (Location loc)
10982 public BaseThis (TypeSpec type, Location loc)
10986 eclass = ExprClass.Variable;
10991 public override string Name {
10999 public override Expression CreateExpressionTree (ResolveContext ec)
11001 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11002 return base.CreateExpressionTree (ec);
11005 public override void Emit (EmitContext ec)
11009 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11010 var context_type = ec.CurrentType;
11011 ec.Emit (OpCodes.Ldobj, context_type);
11012 ec.Emit (OpCodes.Box, context_type);
11016 protected override void Error_ThisNotAvailable (ResolveContext ec)
11019 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11021 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11025 public override void ResolveBase (ResolveContext ec)
11027 base.ResolveBase (ec);
11028 type = ec.CurrentType.BaseType;
11031 public override object Accept (StructuralVisitor visitor)
11033 return visitor.Visit (this);
11038 /// This class exists solely to pass the Type around and to be a dummy
11039 /// that can be passed to the conversion functions (this is used by
11040 /// foreach implementation to typecast the object return value from
11041 /// get_Current into the proper type. All code has been generated and
11042 /// we only care about the side effect conversions to be performed
11044 /// This is also now used as a placeholder where a no-action expression
11045 /// is needed (the `New' class).
11047 public class EmptyExpression : Expression
11049 sealed class OutAccessExpression : EmptyExpression
11051 public OutAccessExpression (TypeSpec t)
11056 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11058 rc.Report.Error (206, right_side.Location,
11059 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11065 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11066 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11067 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11068 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11069 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11070 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11071 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11072 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11074 public EmptyExpression (TypeSpec t)
11077 eclass = ExprClass.Value;
11078 loc = Location.Null;
11081 protected override void CloneTo (CloneContext clonectx, Expression target)
11085 public override bool ContainsEmitWithAwait ()
11090 public override Expression CreateExpressionTree (ResolveContext ec)
11092 throw new NotSupportedException ("ET");
11095 protected override Expression DoResolve (ResolveContext ec)
11100 public override void Emit (EmitContext ec)
11102 // nothing, as we only exist to not do anything.
11105 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11109 public override void EmitSideEffect (EmitContext ec)
11113 public override object Accept (StructuralVisitor visitor)
11115 return visitor.Visit (this);
11119 sealed class EmptyAwaitExpression : EmptyExpression
11121 public EmptyAwaitExpression (TypeSpec type)
11126 public override bool ContainsEmitWithAwait ()
11133 // Empty statement expression
11135 public sealed class EmptyExpressionStatement : ExpressionStatement
11137 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11139 private EmptyExpressionStatement ()
11141 loc = Location.Null;
11144 public override bool ContainsEmitWithAwait ()
11149 public override Expression CreateExpressionTree (ResolveContext ec)
11154 public override void EmitStatement (EmitContext ec)
11159 protected override Expression DoResolve (ResolveContext ec)
11161 eclass = ExprClass.Value;
11162 type = ec.BuiltinTypes.Object;
11166 public override void Emit (EmitContext ec)
11171 public override object Accept (StructuralVisitor visitor)
11173 return visitor.Visit (this);
11177 public class ErrorExpression : EmptyExpression
11179 public static readonly ErrorExpression Instance = new ErrorExpression ();
11181 private ErrorExpression ()
11182 : base (InternalType.ErrorType)
11186 public override Expression CreateExpressionTree (ResolveContext ec)
11191 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11196 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11200 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11204 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11208 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11212 public override object Accept (StructuralVisitor visitor)
11214 return visitor.Visit (this);
11218 public class UserCast : Expression {
11222 public UserCast (MethodSpec method, Expression source, Location l)
11224 if (source == null)
11225 throw new ArgumentNullException ("source");
11227 this.method = method;
11228 this.source = source;
11229 type = method.ReturnType;
11233 public Expression Source {
11242 public override bool ContainsEmitWithAwait ()
11244 return source.ContainsEmitWithAwait ();
11247 public override Expression CreateExpressionTree (ResolveContext ec)
11249 Arguments args = new Arguments (3);
11250 args.Add (new Argument (source.CreateExpressionTree (ec)));
11251 args.Add (new Argument (new TypeOf (type, loc)));
11252 args.Add (new Argument (new TypeOfMethod (method, loc)));
11253 return CreateExpressionFactoryCall (ec, "Convert", args);
11256 protected override Expression DoResolve (ResolveContext ec)
11258 method.CheckObsoleteness (ec, source.Location);
11260 eclass = ExprClass.Value;
11264 public override void Emit (EmitContext ec)
11267 ec.MarkCallEntry (loc);
11268 ec.Emit (OpCodes.Call, method);
11271 public override void FlowAnalysis (FlowAnalysisContext fc)
11273 source.FlowAnalysis (fc);
11276 public override string GetSignatureForError ()
11278 return TypeManager.CSharpSignature (method);
11281 public override SLE.Expression MakeExpression (BuilderContext ctx)
11284 return base.MakeExpression (ctx);
11286 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11292 // Holds additional type specifiers like ?, *, []
11294 public class ComposedTypeSpecifier
11296 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11298 public readonly int Dimension;
11299 public readonly Location Location;
11301 public ComposedTypeSpecifier (int specifier, Location loc)
11303 this.Dimension = specifier;
11304 this.Location = loc;
11308 public bool IsNullable {
11310 return Dimension == -1;
11314 public bool IsPointer {
11316 return Dimension == -2;
11320 public ComposedTypeSpecifier Next { get; set; }
11324 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11326 return new ComposedTypeSpecifier (dimension, loc);
11329 public static ComposedTypeSpecifier CreateNullable (Location loc)
11331 return new ComposedTypeSpecifier (-1, loc);
11334 public static ComposedTypeSpecifier CreatePointer (Location loc)
11336 return new ComposedTypeSpecifier (-2, loc);
11339 public string GetSignatureForError ()
11344 ArrayContainer.GetPostfixSignature (Dimension);
11346 return Next != null ? s + Next.GetSignatureForError () : s;
11351 // This class is used to "construct" the type during a typecast
11352 // operation. Since the Type.GetType class in .NET can parse
11353 // the type specification, we just use this to construct the type
11354 // one bit at a time.
11356 public class ComposedCast : TypeExpr {
11357 FullNamedExpression left;
11358 ComposedTypeSpecifier spec;
11360 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11363 throw new ArgumentNullException ("spec");
11367 this.loc = left.Location;
11370 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11372 type = left.ResolveAsType (ec);
11376 eclass = ExprClass.Type;
11378 var single_spec = spec;
11380 if (single_spec.IsNullable) {
11381 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11385 single_spec = single_spec.Next;
11386 } else if (single_spec.IsPointer) {
11388 // Declared fields cannot have unmanaged check done before all types are defined
11390 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11393 if (!ec.IsUnsafe) {
11394 UnsafeError (ec.Module.Compiler.Report, loc);
11398 type = PointerContainer.MakeType (ec.Module, type);
11399 single_spec = single_spec.Next;
11400 } while (single_spec != null && single_spec.IsPointer);
11403 if (single_spec != null && single_spec.Dimension > 0) {
11404 if (type.IsSpecialRuntimeType) {
11405 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11406 } else if (type.IsStatic) {
11407 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11408 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11409 type.GetSignatureForError ());
11411 MakeArray (ec.Module, single_spec);
11418 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11420 if (spec.Next != null)
11421 MakeArray (module, spec.Next);
11423 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11426 public override string GetSignatureForError ()
11428 return left.GetSignatureForError () + spec.GetSignatureForError ();
11431 public override object Accept (StructuralVisitor visitor)
11433 return visitor.Visit (this);
11437 class FixedBufferPtr : Expression
11439 readonly Expression array;
11441 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11443 this.type = array_type;
11444 this.array = array;
11448 public override bool ContainsEmitWithAwait ()
11450 throw new NotImplementedException ();
11453 public override Expression CreateExpressionTree (ResolveContext ec)
11455 Error_PointerInsideExpressionTree (ec);
11459 public override void Emit(EmitContext ec)
11464 protected override Expression DoResolve (ResolveContext ec)
11466 type = PointerContainer.MakeType (ec.Module, type);
11467 eclass = ExprClass.Value;
11474 // This class is used to represent the address of an array, used
11475 // only by the Fixed statement, this generates "&a [0]" construct
11476 // for fixed (char *pa = a)
11478 class ArrayPtr : FixedBufferPtr
11480 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11481 base (array, array_type, l)
11485 public override void Emit (EmitContext ec)
11490 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11495 // Encapsulates a conversion rules required for array indexes
11497 public class ArrayIndexCast : TypeCast
11499 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11500 : base (expr, returnType)
11502 if (expr.Type == returnType) // int -> int
11503 throw new ArgumentException ("unnecessary array index conversion");
11506 public override Expression CreateExpressionTree (ResolveContext ec)
11508 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11509 return base.CreateExpressionTree (ec);
11513 public override void Emit (EmitContext ec)
11517 switch (child.Type.BuiltinType) {
11518 case BuiltinTypeSpec.Type.UInt:
11519 ec.Emit (OpCodes.Conv_U);
11521 case BuiltinTypeSpec.Type.Long:
11522 ec.Emit (OpCodes.Conv_Ovf_I);
11524 case BuiltinTypeSpec.Type.ULong:
11525 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11528 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11534 // Implements the `stackalloc' keyword
11536 public class StackAlloc : Expression {
11541 public StackAlloc (Expression type, Expression count, Location l)
11544 this.count = count;
11548 public Expression TypeExpression {
11554 public Expression CountExpression {
11560 public override bool ContainsEmitWithAwait ()
11565 public override Expression CreateExpressionTree (ResolveContext ec)
11567 throw new NotSupportedException ("ET");
11570 protected override Expression DoResolve (ResolveContext ec)
11572 count = count.Resolve (ec);
11576 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11577 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11582 Constant c = count as Constant;
11583 if (c != null && c.IsNegative) {
11584 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11587 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11588 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11591 otype = texpr.ResolveAsType (ec);
11595 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11598 type = PointerContainer.MakeType (ec.Module, otype);
11599 eclass = ExprClass.Value;
11604 public override void Emit (EmitContext ec)
11606 int size = BuiltinTypeSpec.GetSize (otype);
11611 ec.Emit (OpCodes.Sizeof, otype);
11615 ec.Emit (OpCodes.Mul_Ovf_Un);
11616 ec.Emit (OpCodes.Localloc);
11619 protected override void CloneTo (CloneContext clonectx, Expression t)
11621 StackAlloc target = (StackAlloc) t;
11622 target.count = count.Clone (clonectx);
11623 target.texpr = texpr.Clone (clonectx);
11626 public override object Accept (StructuralVisitor visitor)
11628 return visitor.Visit (this);
11633 // An object initializer expression
11635 public class ElementInitializer : Assign
11637 public readonly string Name;
11639 public ElementInitializer (string name, Expression initializer, Location loc)
11640 : base (null, initializer, loc)
11645 public bool IsDictionaryInitializer {
11647 return Name == null;
11651 protected override void CloneTo (CloneContext clonectx, Expression t)
11653 ElementInitializer target = (ElementInitializer) t;
11654 target.source = source.Clone (clonectx);
11657 public override Expression CreateExpressionTree (ResolveContext ec)
11659 Arguments args = new Arguments (2);
11660 FieldExpr fe = target as FieldExpr;
11662 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11664 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11667 Expression arg_expr;
11668 var cinit = source as CollectionOrObjectInitializers;
11669 if (cinit == null) {
11671 arg_expr = source.CreateExpressionTree (ec);
11673 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11674 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11677 args.Add (new Argument (arg_expr));
11678 return CreateExpressionFactoryCall (ec, mname, args);
11681 protected override Expression DoResolve (ResolveContext ec)
11683 if (source == null)
11684 return EmptyExpressionStatement.Instance;
11686 if (!ResolveElement (ec))
11689 if (source is CollectionOrObjectInitializers) {
11690 target = target.Resolve (ec);
11691 if (target == null)
11694 Expression previous = ec.CurrentInitializerVariable;
11695 ec.CurrentInitializerVariable = target;
11696 source = source.Resolve (ec);
11697 ec.CurrentInitializerVariable = previous;
11698 if (source == null)
11701 eclass = source.eclass;
11702 type = source.Type;
11707 return base.DoResolve (ec);
11710 public override void EmitStatement (EmitContext ec)
11712 if (source is CollectionOrObjectInitializers)
11715 base.EmitStatement (ec);
11718 protected virtual bool ResolveElement (ResolveContext rc)
11720 var t = rc.CurrentInitializerVariable.Type;
11721 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11722 Arguments args = new Arguments (1);
11723 args.Add (new Argument (rc.CurrentInitializerVariable));
11724 target = new DynamicMemberBinder (Name, args, loc);
11726 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11727 if (member == null) {
11728 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11730 if (member != null) {
11731 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11732 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11737 if (member == null) {
11738 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11742 var me = member as MemberExpr;
11743 if (me is EventExpr) {
11744 me = me.ResolveMemberAccess (rc, null, null);
11745 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11746 rc.Report.Error (1913, loc,
11747 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11748 member.GetSignatureForError ());
11754 rc.Report.Error (1914, loc,
11755 "Static field or property `{0}' cannot be assigned in an object initializer",
11756 me.GetSignatureForError ());
11760 me.InstanceExpression = rc.CurrentInitializerVariable;
11768 // A collection initializer expression
11770 class CollectionElementInitializer : Invocation
11772 public class ElementInitializerArgument : Argument
11774 public ElementInitializerArgument (Expression e)
11780 sealed class AddMemberAccess : MemberAccess
11782 public AddMemberAccess (Expression expr, Location loc)
11783 : base (expr, "Add", loc)
11787 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11789 if (TypeManager.HasElementType (type))
11792 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11796 public CollectionElementInitializer (Expression argument)
11797 : base (null, new Arguments (1))
11799 base.arguments.Add (new ElementInitializerArgument (argument));
11800 this.loc = argument.Location;
11803 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11804 : base (null, new Arguments (arguments.Count))
11806 foreach (Expression e in arguments)
11807 base.arguments.Add (new ElementInitializerArgument (e));
11812 public CollectionElementInitializer (Location loc)
11813 : base (null, null)
11818 public override Expression CreateExpressionTree (ResolveContext ec)
11820 Arguments args = new Arguments (2);
11821 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11823 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11824 foreach (Argument a in arguments) {
11825 if (a.ArgType == Argument.AType.ExtensionType) {
11826 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11829 expr_initializers.Add (a.CreateExpressionTree (ec));
11832 args.Add (new Argument (new ArrayCreation (
11833 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11834 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11837 protected override void CloneTo (CloneContext clonectx, Expression t)
11839 CollectionElementInitializer target = (CollectionElementInitializer) t;
11840 if (arguments != null)
11841 target.arguments = arguments.Clone (clonectx);
11844 protected override Expression DoResolve (ResolveContext ec)
11846 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11848 return base.DoResolve (ec);
11852 class DictionaryElementInitializer : ElementInitializer
11854 readonly Arguments args;
11856 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11857 : base (null, initializer, loc)
11859 this.args = arguments;
11862 public override Expression CreateExpressionTree (ResolveContext ec)
11864 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11868 protected override bool ResolveElement (ResolveContext rc)
11870 var init = rc.CurrentInitializerVariable;
11871 var type = init.Type;
11873 if (type.IsArray) {
11874 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11878 if (type.IsPointer) {
11879 target = init.MakePointerAccess (rc, type, args);
11883 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11884 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11885 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11889 target = new IndexerExpr (indexers, type, init, args, loc);
11895 // A block of object or collection initializers
11897 public class CollectionOrObjectInitializers : ExpressionStatement
11899 IList<Expression> initializers;
11900 bool is_collection_initialization;
11902 public CollectionOrObjectInitializers (Location loc)
11903 : this (new Expression[0], loc)
11907 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11909 this.initializers = initializers;
11913 public IList<Expression> Initializers {
11915 return initializers;
11919 public bool IsEmpty {
11921 return initializers.Count == 0;
11925 public bool IsCollectionInitializer {
11927 return is_collection_initialization;
11931 protected override void CloneTo (CloneContext clonectx, Expression target)
11933 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11935 t.initializers = new List<Expression> (initializers.Count);
11936 foreach (var e in initializers)
11937 t.initializers.Add (e.Clone (clonectx));
11940 public override bool ContainsEmitWithAwait ()
11942 foreach (var e in initializers) {
11943 if (e.ContainsEmitWithAwait ())
11950 public override Expression CreateExpressionTree (ResolveContext ec)
11952 return CreateExpressionTree (ec, false);
11955 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11957 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11958 foreach (Expression e in initializers) {
11959 Expression expr = e.CreateExpressionTree (ec);
11961 expr_initializers.Add (expr);
11965 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11967 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11970 protected override Expression DoResolve (ResolveContext ec)
11972 List<string> element_names = null;
11973 for (int i = 0; i < initializers.Count; ++i) {
11974 Expression initializer = initializers [i];
11975 ElementInitializer element_initializer = initializer as ElementInitializer;
11978 if (element_initializer != null) {
11979 element_names = new List<string> (initializers.Count);
11980 if (!element_initializer.IsDictionaryInitializer)
11981 element_names.Add (element_initializer.Name);
11982 } else if (initializer is CompletingExpression) {
11983 initializer.Resolve (ec);
11984 throw new InternalErrorException ("This line should never be reached");
11986 var t = ec.CurrentInitializerVariable.Type;
11987 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11988 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11989 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11990 "object initializer because type `{1}' does not implement `{2}' interface",
11991 ec.CurrentInitializerVariable.GetSignatureForError (),
11992 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11993 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11996 is_collection_initialization = true;
11999 if (is_collection_initialization != (element_initializer == null)) {
12000 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12001 is_collection_initialization ? "collection initializer" : "object initializer");
12005 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12006 if (element_names.Contains (element_initializer.Name)) {
12007 ec.Report.Error (1912, element_initializer.Location,
12008 "An object initializer includes more than one member `{0}' initialization",
12009 element_initializer.Name);
12011 element_names.Add (element_initializer.Name);
12016 Expression e = initializer.Resolve (ec);
12017 if (e == EmptyExpressionStatement.Instance)
12018 initializers.RemoveAt (i--);
12020 initializers [i] = e;
12023 type = ec.CurrentInitializerVariable.Type;
12024 if (is_collection_initialization) {
12025 if (TypeManager.HasElementType (type)) {
12026 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12027 type.GetSignatureForError ());
12031 eclass = ExprClass.Variable;
12035 public override void Emit (EmitContext ec)
12037 EmitStatement (ec);
12040 public override void EmitStatement (EmitContext ec)
12042 foreach (ExpressionStatement e in initializers) {
12043 // TODO: need location region
12044 ec.Mark (e.Location);
12045 e.EmitStatement (ec);
12049 public override void FlowAnalysis (FlowAnalysisContext fc)
12051 foreach (var initializer in initializers) {
12052 if (initializer != null)
12053 initializer.FlowAnalysis (fc);
12059 // New expression with element/object initializers
12061 public class NewInitialize : New
12064 // This class serves as a proxy for variable initializer target instances.
12065 // A real variable is assigned later when we resolve left side of an
12068 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12070 NewInitialize new_instance;
12072 public InitializerTargetExpression (NewInitialize newInstance)
12074 this.type = newInstance.type;
12075 this.loc = newInstance.loc;
12076 this.eclass = newInstance.eclass;
12077 this.new_instance = newInstance;
12080 public override bool ContainsEmitWithAwait ()
12085 public override Expression CreateExpressionTree (ResolveContext ec)
12087 // Should not be reached
12088 throw new NotSupportedException ("ET");
12091 protected override Expression DoResolve (ResolveContext ec)
12096 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12101 public override void Emit (EmitContext ec)
12103 Expression e = (Expression) new_instance.instance;
12107 public override Expression EmitToField (EmitContext ec)
12109 return (Expression) new_instance.instance;
12112 #region IMemoryLocation Members
12114 public void AddressOf (EmitContext ec, AddressOp mode)
12116 new_instance.instance.AddressOf (ec, mode);
12122 CollectionOrObjectInitializers initializers;
12123 IMemoryLocation instance;
12124 DynamicExpressionStatement dynamic;
12126 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12127 : base (requested_type, arguments, l)
12129 this.initializers = initializers;
12132 public CollectionOrObjectInitializers Initializers {
12134 return initializers;
12138 protected override void CloneTo (CloneContext clonectx, Expression t)
12140 base.CloneTo (clonectx, t);
12142 NewInitialize target = (NewInitialize) t;
12143 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12146 public override bool ContainsEmitWithAwait ()
12148 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12151 public override Expression CreateExpressionTree (ResolveContext ec)
12153 Arguments args = new Arguments (2);
12154 args.Add (new Argument (base.CreateExpressionTree (ec)));
12155 if (!initializers.IsEmpty)
12156 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12158 return CreateExpressionFactoryCall (ec,
12159 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12163 protected override Expression DoResolve (ResolveContext ec)
12165 Expression e = base.DoResolve (ec);
12169 if (type.IsDelegate) {
12170 ec.Report.Error (1958, Initializers.Location,
12171 "Object and collection initializers cannot be used to instantiate a delegate");
12174 Expression previous = ec.CurrentInitializerVariable;
12175 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12176 initializers.Resolve (ec);
12177 ec.CurrentInitializerVariable = previous;
12179 dynamic = e as DynamicExpressionStatement;
12180 if (dynamic != null)
12186 public override void Emit (EmitContext ec)
12188 if (!CanEmitOptimizedLocalTarget (ec)) {
12189 var fe = ec.GetTemporaryField (type);
12191 if (!Emit (ec, fe))
12200 public override bool Emit (EmitContext ec, IMemoryLocation target)
12203 // Expression is initialized into temporary target then moved
12204 // to real one for atomicity
12206 IMemoryLocation temp_target = target;
12208 LocalTemporary temp = null;
12209 bool by_ref = false;
12210 if (!initializers.IsEmpty) {
12211 temp_target = target as LocalTemporary;
12212 if (temp_target == null)
12213 temp_target = target as StackFieldExpr;
12215 if (temp_target == null) {
12216 var vr = target as VariableReference;
12217 if (vr != null && vr.IsRef) {
12223 if (temp_target == null)
12224 temp_target = temp = new LocalTemporary (type);
12227 bool left_on_stack;
12228 if (dynamic != null) {
12230 left_on_stack = true;
12232 left_on_stack = base.Emit (ec, temp_target);
12235 if (initializers.IsEmpty)
12236 return left_on_stack;
12238 StackFieldExpr sf = null;
12240 // Move a new instance (reference-type) to local temporary variable
12241 if (left_on_stack) {
12243 temp_target = temp = new LocalTemporary (type);
12249 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12251 throw new NotImplementedException ();
12253 sf = ec.GetTemporaryField (type);
12254 sf.AutomaticallyReuse = false;
12255 sf.EmitAssign (ec, temp, false, false);
12258 left_on_stack = false;
12262 instance = temp_target;
12264 initializers.Emit (ec);
12266 ((Expression)temp_target).Emit (ec);
12272 sf.PrepareCleanup (ec);
12277 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12279 return !(method == null && TypeSpec.IsValueType (type) &&
12280 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12281 initializers.ContainsEmitWithAwait ());
12284 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12286 instance = base.EmitAddressOf (ec, Mode);
12288 if (!initializers.IsEmpty)
12289 initializers.Emit (ec);
12294 public override void FlowAnalysis (FlowAnalysisContext fc)
12296 base.FlowAnalysis (fc);
12297 initializers.FlowAnalysis (fc);
12300 public override object Accept (StructuralVisitor visitor)
12302 return visitor.Visit (this);
12306 public class NewAnonymousType : New
12308 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12310 List<AnonymousTypeParameter> parameters;
12311 readonly TypeContainer parent;
12312 AnonymousTypeClass anonymous_type;
12314 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12315 : base (null, null, loc)
12317 this.parameters = parameters;
12318 this.parent = parent;
12321 public List<AnonymousTypeParameter> Parameters {
12323 return this.parameters;
12327 protected override void CloneTo (CloneContext clonectx, Expression target)
12329 if (parameters == null)
12332 NewAnonymousType t = (NewAnonymousType) target;
12333 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12334 foreach (AnonymousTypeParameter atp in parameters)
12335 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12338 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12340 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12344 type = AnonymousTypeClass.Create (parent, parameters, loc);
12348 int errors = ec.Report.Errors;
12349 type.CreateContainer ();
12350 type.DefineContainer ();
12352 if ((ec.Report.Errors - errors) == 0) {
12353 parent.Module.AddAnonymousType (type);
12354 type.PrepareEmit ();
12360 public override Expression CreateExpressionTree (ResolveContext ec)
12362 if (parameters == null)
12363 return base.CreateExpressionTree (ec);
12365 var init = new ArrayInitializer (parameters.Count, loc);
12366 foreach (var m in anonymous_type.Members) {
12367 var p = m as Property;
12369 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12372 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12373 foreach (Argument a in arguments)
12374 ctor_args.Add (a.CreateExpressionTree (ec));
12376 Arguments args = new Arguments (3);
12377 args.Add (new Argument (new TypeOfMethod (method, loc)));
12378 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12379 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12381 return CreateExpressionFactoryCall (ec, "New", args);
12384 protected override Expression DoResolve (ResolveContext ec)
12386 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12387 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12391 if (parameters == null) {
12392 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12393 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12394 return base.DoResolve (ec);
12397 bool error = false;
12398 arguments = new Arguments (parameters.Count);
12399 var t_args = new TypeSpec [parameters.Count];
12400 for (int i = 0; i < parameters.Count; ++i) {
12401 Expression e = parameters [i].Resolve (ec);
12407 arguments.Add (new Argument (e));
12408 t_args [i] = e.Type;
12414 anonymous_type = CreateAnonymousType (ec, parameters);
12415 if (anonymous_type == null)
12418 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12419 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12420 eclass = ExprClass.Value;
12424 public override object Accept (StructuralVisitor visitor)
12426 return visitor.Visit (this);
12430 public class AnonymousTypeParameter : ShimExpression
12432 public readonly string Name;
12434 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12435 : base (initializer)
12441 public AnonymousTypeParameter (Parameter parameter)
12442 : base (new SimpleName (parameter.Name, parameter.Location))
12444 this.Name = parameter.Name;
12445 this.loc = parameter.Location;
12448 public override bool Equals (object o)
12450 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12451 return other != null && Name == other.Name;
12454 public override int GetHashCode ()
12456 return Name.GetHashCode ();
12459 protected override Expression DoResolve (ResolveContext ec)
12461 Expression e = expr.Resolve (ec);
12465 if (e.eclass == ExprClass.MethodGroup) {
12466 Error_InvalidInitializer (ec, e.ExprClassName);
12471 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12472 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12479 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12481 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12482 Name, initializer);
12486 public class CatchFilterExpression : BooleanExpression
12488 public CatchFilterExpression (Expression expr, Location loc)
12495 public class InterpolatedString : Expression
12497 readonly StringLiteral start, end;
12498 List<Expression> interpolations;
12499 Arguments arguments;
12501 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12503 this.start = start;
12505 this.interpolations = interpolations;
12506 loc = start.Location;
12509 protected override void CloneTo (CloneContext clonectx, Expression t)
12511 InterpolatedString target = (InterpolatedString) t;
12513 if (interpolations != null) {
12514 target.interpolations = new List<Expression> ();
12515 foreach (var interpolation in interpolations) {
12516 target.interpolations.Add (interpolation.Clone (clonectx));
12521 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12523 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12524 if (factory == null)
12527 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12528 var res = new Invocation (ma, arguments).Resolve (rc);
12529 if (res != null && res.Type != type)
12530 res = Convert.ExplicitConversion (rc, res, type, loc);
12535 public override bool ContainsEmitWithAwait ()
12537 if (interpolations == null)
12540 foreach (var expr in interpolations) {
12541 if (expr.ContainsEmitWithAwait ())
12548 public override Expression CreateExpressionTree (ResolveContext rc)
12550 var best = ResolveBestFormatOverload (rc);
12554 Expression instance = new NullLiteral (loc);
12555 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12556 return CreateExpressionFactoryCall (rc, "Call", args);
12559 protected override Expression DoResolve (ResolveContext rc)
12563 if (interpolations == null) {
12565 arguments = new Arguments (1);
12567 arguments = new Arguments (interpolations.Count);
12569 var sb = new StringBuilder (start.Value);
12570 for (int i = 0; i < interpolations.Count; ++i) {
12572 sb.Append ('{').Append (i / 2);
12573 var isi = (InterpolatedStringInsert)interpolations [i];
12574 if (isi.Alignment != null) {
12576 var value = isi.ResolveAligment (rc);
12578 sb.Append (value.Value);
12581 if (isi.Format != null) {
12583 sb.Append (isi.Format);
12587 arguments.Add (new Argument (isi.Resolve (rc)));
12589 sb.Append (((StringLiteral)interpolations [i]).Value);
12593 sb.Append (end.Value);
12594 str = sb.ToString ();
12597 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12599 eclass = ExprClass.Value;
12600 type = rc.BuiltinTypes.String;
12604 public override void Emit (EmitContext ec)
12606 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12607 if (interpolations == null) {
12608 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12609 if (str != start.Value)
12610 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12617 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12621 var ca = new CallEmitter ();
12622 ca.Emit (ec, best, arguments, loc);
12625 public override void FlowAnalysis (FlowAnalysisContext fc)
12627 if (interpolations != null) {
12628 foreach (var expr in interpolations) {
12629 expr.FlowAnalysis (fc);
12634 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12636 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12637 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12638 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12642 public class InterpolatedStringInsert : CompositeExpression
12644 public InterpolatedStringInsert (Expression expr)
12649 public Expression Alignment { get; set; }
12650 public string Format { get; set; }
12652 protected override void CloneTo (CloneContext clonectx, Expression t)
12654 var target = (InterpolatedStringInsert)t;
12655 target.expr = expr.Clone (clonectx);
12656 if (Alignment != null)
12657 target.Alignment = Alignment.Clone (clonectx);
12660 protected override Expression DoResolve (ResolveContext rc)
12662 var expr = base.DoResolve (rc);
12667 // For better error reporting, assumes the built-in implementation uses object
12670 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12673 public override void FlowAnalysis (FlowAnalysisContext fc)
12675 Child.FlowAnalysis (fc);
12678 public int? ResolveAligment (ResolveContext rc)
12680 var c = Alignment.ResolveLabelConstant (rc);
12684 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12688 var value = (int) c.GetValueAsLong ();
12689 if (value > 32767 || value < -32767) {
12690 rc.Report.Warning (8094, 1, Alignment.Location,
12691 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");