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 protected override Expression DoResolve (ResolveContext rc)
7028 ResolveConditionalAccessReceiver (rc);
7029 return DoResolveInvocation (rc);
7032 Expression DoResolveInvocation (ResolveContext ec)
7034 Expression member_expr;
7035 var atn = expr as ATypeNameExpression;
7037 var flags = default (ResolveContext.FlagsHandle);
7038 if (conditional_access_receiver)
7039 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7042 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7043 if (member_expr != null) {
7044 var name_of = member_expr as NameOf;
7045 if (name_of != null) {
7046 return name_of.ResolveOverload (ec, arguments);
7049 member_expr = member_expr.Resolve (ec);
7052 member_expr = expr.Resolve (ec);
7055 if (conditional_access_receiver)
7058 if (member_expr == null)
7062 // Next, evaluate all the expressions in the argument list
7064 bool dynamic_arg = false;
7065 if (arguments != null) {
7066 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7067 arguments.Resolve (ec, out dynamic_arg);
7071 TypeSpec expr_type = member_expr.Type;
7072 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7073 return DoResolveDynamic (ec, member_expr);
7075 mg = member_expr as MethodGroupExpr;
7076 Expression invoke = null;
7079 if (expr_type != null && expr_type.IsDelegate) {
7080 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7081 invoke = invoke.Resolve (ec);
7082 if (invoke == null || !dynamic_arg)
7085 if (member_expr is RuntimeValueExpression) {
7086 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7087 member_expr.Type.GetSignatureForError ());
7091 MemberExpr me = member_expr as MemberExpr;
7093 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7097 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7098 member_expr.GetSignatureForError ());
7103 if (invoke == null) {
7104 mg = DoResolveOverload (ec);
7110 return DoResolveDynamic (ec, member_expr);
7112 var method = mg.BestCandidate;
7113 type = mg.BestCandidateReturnType;
7114 if (conditional_access_receiver)
7115 type = LiftMemberType (ec, type);
7117 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7119 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7121 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7125 IsSpecialMethodInvocation (ec, method, loc);
7127 eclass = ExprClass.Value;
7131 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7134 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7136 args = dmb.Arguments;
7137 if (arguments != null)
7138 args.AddRange (arguments);
7139 } else if (mg == null) {
7140 if (arguments == null)
7141 args = new Arguments (1);
7145 args.Insert (0, new Argument (memberExpr));
7149 ec.Report.Error (1971, loc,
7150 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7155 if (arguments == null)
7156 args = new Arguments (1);
7160 MemberAccess ma = expr as MemberAccess;
7162 var inst = mg.InstanceExpression;
7163 var left_type = inst as TypeExpr;
7164 if (left_type != null) {
7165 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7166 } else if (inst != null) {
7168 // Any value type has to be pass as by-ref to get back the same
7169 // instance on which the member was called
7171 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7172 Argument.AType.Ref : Argument.AType.None;
7173 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7175 } else { // is SimpleName
7177 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7179 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7184 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7187 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7189 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7192 public override void FlowAnalysis (FlowAnalysisContext fc)
7194 if (mg.IsConditionallyExcluded)
7197 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7199 mg.FlowAnalysis (fc);
7201 if (arguments != null)
7202 arguments.FlowAnalysis (fc);
7204 if (conditional_access_receiver)
7205 fc.DefiniteAssignment = da;
7208 public override string GetSignatureForError ()
7210 return mg.GetSignatureForError ();
7213 public override bool HasConditionalAccess ()
7215 return expr.HasConditionalAccess ();
7219 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7220 // or the type dynamic, then the member is invocable
7222 public static bool IsMemberInvocable (MemberSpec member)
7224 switch (member.Kind) {
7225 case MemberKind.Event:
7227 case MemberKind.Field:
7228 case MemberKind.Property:
7229 var m = member as IInterfaceMemberSpec;
7230 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7236 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7238 if (!method.IsReservedMethod)
7241 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7244 ec.Report.SymbolRelatedToPreviousError (method);
7245 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7246 method.GetSignatureForError ());
7251 public override void Emit (EmitContext ec)
7253 if (mg.IsConditionallyExcluded)
7256 if (conditional_access_receiver)
7257 mg.EmitCall (ec, arguments, type, false);
7259 mg.EmitCall (ec, arguments, false);
7262 public override void EmitStatement (EmitContext ec)
7264 if (mg.IsConditionallyExcluded)
7267 if (conditional_access_receiver)
7268 mg.EmitCall (ec, arguments, type, true);
7270 mg.EmitCall (ec, arguments, true);
7273 public override SLE.Expression MakeExpression (BuilderContext ctx)
7275 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7278 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7281 throw new NotSupportedException ();
7283 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7284 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7288 public override object Accept (StructuralVisitor visitor)
7290 return visitor.Visit (this);
7295 // Implements simple new expression
7297 public class New : ExpressionStatement, IMemoryLocation
7299 protected Arguments arguments;
7302 // During bootstrap, it contains the RequestedType,
7303 // but if `type' is not null, it *might* contain a NewDelegate
7304 // (because of field multi-initialization)
7306 protected Expression RequestedType;
7308 protected MethodSpec method;
7310 public New (Expression requested_type, Arguments arguments, Location l)
7312 RequestedType = requested_type;
7313 this.arguments = arguments;
7318 public Arguments Arguments {
7325 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7327 public bool IsGeneratedStructConstructor {
7329 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7333 public Expression TypeExpression {
7335 return RequestedType;
7342 /// Converts complex core type syntax like 'new int ()' to simple constant
7344 public static Constant Constantify (TypeSpec t, Location loc)
7346 switch (t.BuiltinType) {
7347 case BuiltinTypeSpec.Type.Int:
7348 return new IntConstant (t, 0, loc);
7349 case BuiltinTypeSpec.Type.UInt:
7350 return new UIntConstant (t, 0, loc);
7351 case BuiltinTypeSpec.Type.Long:
7352 return new LongConstant (t, 0, loc);
7353 case BuiltinTypeSpec.Type.ULong:
7354 return new ULongConstant (t, 0, loc);
7355 case BuiltinTypeSpec.Type.Float:
7356 return new FloatConstant (t, 0, loc);
7357 case BuiltinTypeSpec.Type.Double:
7358 return new DoubleConstant (t, 0, loc);
7359 case BuiltinTypeSpec.Type.Short:
7360 return new ShortConstant (t, 0, loc);
7361 case BuiltinTypeSpec.Type.UShort:
7362 return new UShortConstant (t, 0, loc);
7363 case BuiltinTypeSpec.Type.SByte:
7364 return new SByteConstant (t, 0, loc);
7365 case BuiltinTypeSpec.Type.Byte:
7366 return new ByteConstant (t, 0, loc);
7367 case BuiltinTypeSpec.Type.Char:
7368 return new CharConstant (t, '\0', loc);
7369 case BuiltinTypeSpec.Type.Bool:
7370 return new BoolConstant (t, false, loc);
7371 case BuiltinTypeSpec.Type.Decimal:
7372 return new DecimalConstant (t, 0, loc);
7376 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7378 if (t.IsNullableType)
7379 return Nullable.LiftedNull.Create (t, loc);
7384 public override bool ContainsEmitWithAwait ()
7386 return arguments != null && arguments.ContainsEmitWithAwait ();
7390 // Checks whether the type is an interface that has the
7391 // [ComImport, CoClass] attributes and must be treated
7394 public Expression CheckComImport (ResolveContext ec)
7396 if (!type.IsInterface)
7400 // Turn the call into:
7401 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7403 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7404 if (real_class == null)
7407 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7408 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7409 return cast.Resolve (ec);
7412 public override Expression CreateExpressionTree (ResolveContext ec)
7415 if (method == null) {
7416 args = new Arguments (1);
7417 args.Add (new Argument (new TypeOf (type, loc)));
7419 args = Arguments.CreateForExpressionTree (ec,
7420 arguments, new TypeOfMethod (method, loc));
7423 return CreateExpressionFactoryCall (ec, "New", args);
7426 protected override Expression DoResolve (ResolveContext ec)
7428 type = RequestedType.ResolveAsType (ec);
7432 eclass = ExprClass.Value;
7434 if (type.IsPointer) {
7435 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7436 type.GetSignatureForError ());
7440 if (arguments == null) {
7441 Constant c = Constantify (type, RequestedType.Location);
7443 return ReducedExpression.Create (c, this);
7446 if (type.IsDelegate) {
7447 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7450 var tparam = type as TypeParameterSpec;
7451 if (tparam != null) {
7453 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7454 // where type parameter constraint is inflated to struct
7456 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7457 ec.Report.Error (304, loc,
7458 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7459 type.GetSignatureForError ());
7462 if ((arguments != null) && (arguments.Count != 0)) {
7463 ec.Report.Error (417, loc,
7464 "`{0}': cannot provide arguments when creating an instance of a variable type",
7465 type.GetSignatureForError ());
7471 if (type.IsStatic) {
7472 ec.Report.SymbolRelatedToPreviousError (type);
7473 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7477 if (type.IsInterface || type.IsAbstract){
7478 if (!TypeManager.IsGenericType (type)) {
7479 RequestedType = CheckComImport (ec);
7480 if (RequestedType != null)
7481 return RequestedType;
7484 ec.Report.SymbolRelatedToPreviousError (type);
7485 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7490 if (arguments != null) {
7491 arguments.Resolve (ec, out dynamic);
7496 method = ConstructorLookup (ec, type, ref arguments, loc);
7499 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7500 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7506 void DoEmitTypeParameter (EmitContext ec)
7508 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7512 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7513 ec.Emit (OpCodes.Call, ctor_factory);
7517 // This Emit can be invoked in two contexts:
7518 // * As a mechanism that will leave a value on the stack (new object)
7519 // * As one that wont (init struct)
7521 // If we are dealing with a ValueType, we have a few
7522 // situations to deal with:
7524 // * The target is a ValueType, and we have been provided
7525 // the instance (this is easy, we are being assigned).
7527 // * The target of New is being passed as an argument,
7528 // to a boxing operation or a function that takes a
7531 // In this case, we need to create a temporary variable
7532 // that is the argument of New.
7534 // Returns whether a value is left on the stack
7536 // *** Implementation note ***
7538 // To benefit from this optimization, each assignable expression
7539 // has to manually cast to New and call this Emit.
7541 // TODO: It's worth to implement it for arrays and fields
7543 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7545 bool is_value_type = type.IsStructOrEnum;
7546 VariableReference vr = target as VariableReference;
7548 if (target != null && is_value_type && (vr != null || method == null)) {
7549 target.AddressOf (ec, AddressOp.Store);
7550 } else if (vr != null && vr.IsRef) {
7554 if (arguments != null) {
7555 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7556 arguments = arguments.Emit (ec, false, true);
7558 arguments.Emit (ec);
7561 if (is_value_type) {
7562 if (method == null) {
7563 ec.Emit (OpCodes.Initobj, type);
7568 ec.MarkCallEntry (loc);
7569 ec.Emit (OpCodes.Call, method);
7574 if (type is TypeParameterSpec) {
7575 DoEmitTypeParameter (ec);
7579 ec.MarkCallEntry (loc);
7580 ec.Emit (OpCodes.Newobj, method);
7584 public override void Emit (EmitContext ec)
7586 LocalTemporary v = null;
7587 if (method == null && type.IsStructOrEnum) {
7588 // TODO: Use temporary variable from pool
7589 v = new LocalTemporary (type);
7596 public override void EmitStatement (EmitContext ec)
7598 LocalTemporary v = null;
7599 if (method == null && TypeSpec.IsValueType (type)) {
7600 // TODO: Use temporary variable from pool
7601 v = new LocalTemporary (type);
7605 ec.Emit (OpCodes.Pop);
7608 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7613 public override void FlowAnalysis (FlowAnalysisContext fc)
7615 if (arguments != null)
7616 arguments.FlowAnalysis (fc);
7619 public void AddressOf (EmitContext ec, AddressOp mode)
7621 EmitAddressOf (ec, mode);
7624 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7626 LocalTemporary value_target = new LocalTemporary (type);
7628 if (type is TypeParameterSpec) {
7629 DoEmitTypeParameter (ec);
7630 value_target.Store (ec);
7631 value_target.AddressOf (ec, mode);
7632 return value_target;
7635 value_target.AddressOf (ec, AddressOp.Store);
7637 if (method == null) {
7638 ec.Emit (OpCodes.Initobj, type);
7640 if (arguments != null)
7641 arguments.Emit (ec);
7643 ec.Emit (OpCodes.Call, method);
7646 value_target.AddressOf (ec, mode);
7647 return value_target;
7650 protected override void CloneTo (CloneContext clonectx, Expression t)
7652 New target = (New) t;
7654 target.RequestedType = RequestedType.Clone (clonectx);
7655 if (arguments != null){
7656 target.arguments = arguments.Clone (clonectx);
7660 public override SLE.Expression MakeExpression (BuilderContext ctx)
7663 return base.MakeExpression (ctx);
7665 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7669 public override object Accept (StructuralVisitor visitor)
7671 return visitor.Visit (this);
7676 // Array initializer expression, the expression is allowed in
7677 // variable or field initialization only which makes it tricky as
7678 // the type has to be infered based on the context either from field
7679 // type or variable type (think of multiple declarators)
7681 public class ArrayInitializer : Expression
7683 List<Expression> elements;
7684 BlockVariable variable;
7686 public ArrayInitializer (List<Expression> init, Location loc)
7692 public ArrayInitializer (int count, Location loc)
7693 : this (new List<Expression> (count), loc)
7697 public ArrayInitializer (Location loc)
7705 get { return elements.Count; }
7708 public List<Expression> Elements {
7714 public Expression this [int index] {
7716 return elements [index];
7720 public BlockVariable VariableDeclaration {
7731 public void Add (Expression expr)
7733 elements.Add (expr);
7736 public override bool ContainsEmitWithAwait ()
7738 throw new NotSupportedException ();
7741 public override Expression CreateExpressionTree (ResolveContext ec)
7743 throw new NotSupportedException ("ET");
7746 protected override void CloneTo (CloneContext clonectx, Expression t)
7748 var target = (ArrayInitializer) t;
7750 target.elements = new List<Expression> (elements.Count);
7751 foreach (var element in elements)
7752 target.elements.Add (element.Clone (clonectx));
7755 protected override Expression DoResolve (ResolveContext rc)
7757 var current_field = rc.CurrentMemberDefinition as FieldBase;
7758 TypeExpression type;
7759 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7760 type = new TypeExpression (current_field.MemberType, current_field.Location);
7761 } else if (variable != null) {
7762 if (variable.TypeExpression is VarExpr) {
7763 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7764 return EmptyExpression.Null;
7767 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7769 throw new NotImplementedException ("Unexpected array initializer context");
7772 return new ArrayCreation (type, this).Resolve (rc);
7775 public override void Emit (EmitContext ec)
7777 throw new InternalErrorException ("Missing Resolve call");
7780 public override void FlowAnalysis (FlowAnalysisContext fc)
7782 throw new InternalErrorException ("Missing Resolve call");
7785 public override object Accept (StructuralVisitor visitor)
7787 return visitor.Visit (this);
7792 /// 14.5.10.2: Represents an array creation expression.
7796 /// There are two possible scenarios here: one is an array creation
7797 /// expression that specifies the dimensions and optionally the
7798 /// initialization data and the other which does not need dimensions
7799 /// specified but where initialization data is mandatory.
7801 public class ArrayCreation : Expression
7803 FullNamedExpression requested_base_type;
7804 ArrayInitializer initializers;
7807 // The list of Argument types.
7808 // This is used to construct the `newarray' or constructor signature
7810 protected List<Expression> arguments;
7812 protected TypeSpec array_element_type;
7814 protected int dimensions;
7815 protected readonly ComposedTypeSpecifier rank;
7816 Expression first_emit;
7817 LocalTemporary first_emit_temp;
7819 protected List<Expression> array_data;
7821 Dictionary<int, int> bounds;
7824 // The number of constants in array initializers
7825 int const_initializers_count;
7826 bool only_constant_initializers;
7828 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7829 : this (requested_base_type, rank, initializers, l)
7831 arguments = new List<Expression> (exprs);
7832 num_arguments = arguments.Count;
7836 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7838 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7840 this.requested_base_type = requested_base_type;
7842 this.initializers = initializers;
7846 num_arguments = rank.Dimension;
7850 // For compiler generated single dimensional arrays only
7852 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7853 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7858 // For expressions like int[] foo = { 1, 2, 3 };
7860 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7861 : this (requested_base_type, null, initializers, initializers.Location)
7865 public ComposedTypeSpecifier Rank {
7871 public FullNamedExpression TypeExpression {
7873 return this.requested_base_type;
7877 public ArrayInitializer Initializers {
7879 return this.initializers;
7883 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7885 if (initializers != null && bounds == null) {
7887 // We use this to store all the data values in the order in which we
7888 // will need to store them in the byte blob later
7890 array_data = new List<Expression> (probe.Count);
7891 bounds = new Dictionary<int, int> ();
7894 if (specified_dims) {
7895 Expression a = arguments [idx];
7900 a = ConvertExpressionToArrayIndex (ec, a);
7906 if (initializers != null) {
7907 Constant c = a as Constant;
7908 if (c == null && a is ArrayIndexCast)
7909 c = ((ArrayIndexCast) a).Child as Constant;
7912 ec.Report.Error (150, a.Location, "A constant value is expected");
7918 value = System.Convert.ToInt32 (c.GetValue ());
7920 ec.Report.Error (150, a.Location, "A constant value is expected");
7924 // TODO: probe.Count does not fit ulong in
7925 if (value != probe.Count) {
7926 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7930 bounds[idx] = value;
7934 if (initializers == null)
7937 for (int i = 0; i < probe.Count; ++i) {
7939 if (o is ArrayInitializer) {
7940 var sub_probe = o as ArrayInitializer;
7941 if (idx + 1 >= dimensions){
7942 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7946 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7947 if (!bounds.ContainsKey(idx + 1))
7948 bounds[idx + 1] = sub_probe.Count;
7950 if (bounds[idx + 1] != sub_probe.Count) {
7951 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7955 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7958 } else if (child_bounds > 1) {
7959 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7961 Expression element = ResolveArrayElement (ec, o);
7962 if (element == null)
7965 // Initializers with the default values can be ignored
7966 Constant c = element as Constant;
7968 if (!c.IsDefaultInitializer (array_element_type)) {
7969 ++const_initializers_count;
7972 only_constant_initializers = false;
7975 array_data.Add (element);
7982 public override bool ContainsEmitWithAwait ()
7984 foreach (var arg in arguments) {
7985 if (arg.ContainsEmitWithAwait ())
7989 return InitializersContainAwait ();
7992 public override Expression CreateExpressionTree (ResolveContext ec)
7996 if (array_data == null) {
7997 args = new Arguments (arguments.Count + 1);
7998 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7999 foreach (Expression a in arguments)
8000 args.Add (new Argument (a.CreateExpressionTree (ec)));
8002 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8005 if (dimensions > 1) {
8006 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8010 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8011 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8012 if (array_data != null) {
8013 for (int i = 0; i < array_data.Count; ++i) {
8014 Expression e = array_data [i];
8015 args.Add (new Argument (e.CreateExpressionTree (ec)));
8019 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8022 void UpdateIndices (ResolveContext rc)
8025 for (var probe = initializers; probe != null;) {
8026 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8028 bounds[i++] = probe.Count;
8030 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8031 probe = (ArrayInitializer) probe[0];
8032 } else if (dimensions > i) {
8040 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8042 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8045 public override void FlowAnalysis (FlowAnalysisContext fc)
8047 foreach (var arg in arguments)
8048 arg.FlowAnalysis (fc);
8050 if (array_data != null) {
8051 foreach (var ad in array_data)
8052 ad.FlowAnalysis (fc);
8056 bool InitializersContainAwait ()
8058 if (array_data == null)
8061 foreach (var expr in array_data) {
8062 if (expr.ContainsEmitWithAwait ())
8069 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8071 element = element.Resolve (ec);
8072 if (element == null)
8075 if (element is CompoundAssign.TargetExpression) {
8076 if (first_emit != null)
8077 throw new InternalErrorException ("Can only handle one mutator at a time");
8078 first_emit = element;
8079 element = first_emit_temp = new LocalTemporary (element.Type);
8082 return Convert.ImplicitConversionRequired (
8083 ec, element, array_element_type, loc);
8086 protected bool ResolveInitializers (ResolveContext ec)
8089 only_constant_initializers = true;
8092 if (arguments != null) {
8094 for (int i = 0; i < arguments.Count; ++i) {
8095 res &= CheckIndices (ec, initializers, i, true, dimensions);
8096 if (initializers != null)
8103 arguments = new List<Expression> ();
8105 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8114 // Resolved the type of the array
8116 bool ResolveArrayType (ResolveContext ec)
8121 FullNamedExpression array_type_expr;
8122 if (num_arguments > 0) {
8123 array_type_expr = new ComposedCast (requested_base_type, rank);
8125 array_type_expr = requested_base_type;
8128 type = array_type_expr.ResolveAsType (ec);
8129 if (array_type_expr == null)
8132 var ac = type as ArrayContainer;
8134 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8138 array_element_type = ac.Element;
8139 dimensions = ac.Rank;
8144 protected override Expression DoResolve (ResolveContext ec)
8149 if (!ResolveArrayType (ec))
8153 // validate the initializers and fill in any missing bits
8155 if (!ResolveInitializers (ec))
8158 eclass = ExprClass.Value;
8162 byte [] MakeByteBlob ()
8167 int count = array_data.Count;
8169 TypeSpec element_type = array_element_type;
8170 if (element_type.IsEnum)
8171 element_type = EnumSpec.GetUnderlyingType (element_type);
8173 factor = BuiltinTypeSpec.GetSize (element_type);
8175 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8177 data = new byte [(count * factor + 3) & ~3];
8180 for (int i = 0; i < count; ++i) {
8181 var c = array_data[i] as Constant;
8187 object v = c.GetValue ();
8189 switch (element_type.BuiltinType) {
8190 case BuiltinTypeSpec.Type.Long:
8191 long lval = (long) v;
8193 for (int j = 0; j < factor; ++j) {
8194 data[idx + j] = (byte) (lval & 0xFF);
8198 case BuiltinTypeSpec.Type.ULong:
8199 ulong ulval = (ulong) v;
8201 for (int j = 0; j < factor; ++j) {
8202 data[idx + j] = (byte) (ulval & 0xFF);
8203 ulval = (ulval >> 8);
8206 case BuiltinTypeSpec.Type.Float:
8207 var fval = SingleConverter.SingleToInt32Bits((float) v);
8209 data[idx] = (byte) (fval & 0xff);
8210 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8211 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8212 data[idx + 3] = (byte) (fval >> 24);
8214 case BuiltinTypeSpec.Type.Double:
8215 element = BitConverter.GetBytes ((double) v);
8217 for (int j = 0; j < factor; ++j)
8218 data[idx + j] = element[j];
8220 // FIXME: Handle the ARM float format.
8221 if (!BitConverter.IsLittleEndian)
8222 System.Array.Reverse (data, idx, 8);
8224 case BuiltinTypeSpec.Type.Char:
8225 int chval = (int) ((char) v);
8227 data[idx] = (byte) (chval & 0xff);
8228 data[idx + 1] = (byte) (chval >> 8);
8230 case BuiltinTypeSpec.Type.Short:
8231 int sval = (int) ((short) v);
8233 data[idx] = (byte) (sval & 0xff);
8234 data[idx + 1] = (byte) (sval >> 8);
8236 case BuiltinTypeSpec.Type.UShort:
8237 int usval = (int) ((ushort) v);
8239 data[idx] = (byte) (usval & 0xff);
8240 data[idx + 1] = (byte) (usval >> 8);
8242 case BuiltinTypeSpec.Type.Int:
8245 data[idx] = (byte) (val & 0xff);
8246 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8247 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8248 data[idx + 3] = (byte) (val >> 24);
8250 case BuiltinTypeSpec.Type.UInt:
8251 uint uval = (uint) v;
8253 data[idx] = (byte) (uval & 0xff);
8254 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8255 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8256 data[idx + 3] = (byte) (uval >> 24);
8258 case BuiltinTypeSpec.Type.SByte:
8259 data[idx] = (byte) (sbyte) v;
8261 case BuiltinTypeSpec.Type.Byte:
8262 data[idx] = (byte) v;
8264 case BuiltinTypeSpec.Type.Bool:
8265 data[idx] = (byte) ((bool) v ? 1 : 0);
8267 case BuiltinTypeSpec.Type.Decimal:
8268 int[] bits = Decimal.GetBits ((decimal) v);
8271 // FIXME: For some reason, this doesn't work on the MS runtime.
8272 int[] nbits = new int[4];
8278 for (int j = 0; j < 4; j++) {
8279 data[p++] = (byte) (nbits[j] & 0xff);
8280 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8281 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8282 data[p++] = (byte) (nbits[j] >> 24);
8286 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8295 public override SLE.Expression MakeExpression (BuilderContext ctx)
8298 return base.MakeExpression (ctx);
8300 var initializers = new SLE.Expression [array_data.Count];
8301 for (var i = 0; i < initializers.Length; i++) {
8302 if (array_data [i] == null)
8303 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8305 initializers [i] = array_data [i].MakeExpression (ctx);
8308 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8313 // Emits the initializers for the array
8315 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8317 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8322 // First, the static data
8324 byte [] data = MakeByteBlob ();
8325 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8327 if (stackArray == null) {
8328 ec.Emit (OpCodes.Dup);
8330 stackArray.Emit (ec);
8333 ec.Emit (OpCodes.Ldtoken, fb);
8334 ec.Emit (OpCodes.Call, m);
8339 // Emits pieces of the array that can not be computed at compile
8340 // time (variables and string locations).
8342 // This always expect the top value on the stack to be the array
8344 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8346 int dims = bounds.Count;
8347 var current_pos = new int [dims];
8349 for (int i = 0; i < array_data.Count; i++){
8351 Expression e = array_data [i];
8352 var c = e as Constant;
8354 // Constant can be initialized via StaticInitializer
8355 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8359 if (stackArray != null) {
8360 if (e.ContainsEmitWithAwait ()) {
8361 e = e.EmitToField (ec);
8364 stackArray.EmitLoad (ec);
8366 ec.Emit (OpCodes.Dup);
8369 for (int idx = 0; idx < dims; idx++)
8370 ec.EmitInt (current_pos [idx]);
8373 // If we are dealing with a struct, get the
8374 // address of it, so we can store it.
8376 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8377 ec.Emit (OpCodes.Ldelema, etype);
8381 ec.EmitArrayStore ((ArrayContainer) type);
8387 for (int j = dims - 1; j >= 0; j--){
8389 if (current_pos [j] < bounds [j])
8391 current_pos [j] = 0;
8395 if (stackArray != null)
8396 stackArray.PrepareCleanup (ec);
8399 public override void Emit (EmitContext ec)
8401 if (EmitOptimizedEmpty (ec))
8404 var await_field = EmitToFieldSource (ec);
8405 if (await_field != null)
8406 await_field.Emit (ec);
8409 bool EmitOptimizedEmpty (EmitContext ec)
8411 if (arguments.Count != 1 || dimensions != 1)
8414 var c = arguments [0] as Constant;
8415 if (c == null || !c.IsZeroInteger)
8418 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8419 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8422 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8423 ec.Emit (OpCodes.Call, m);
8427 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8429 if (first_emit != null) {
8430 first_emit.Emit (ec);
8431 first_emit_temp.Store (ec);
8434 StackFieldExpr await_stack_field;
8435 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8436 await_stack_field = ec.GetTemporaryField (type);
8439 await_stack_field = null;
8442 EmitExpressionsList (ec, arguments);
8444 ec.EmitArrayNew ((ArrayContainer) type);
8446 if (initializers == null)
8447 return await_stack_field;
8449 if (await_stack_field != null)
8450 await_stack_field.EmitAssignFromStack (ec);
8454 // Emit static initializer for arrays which contain more than 2 items and
8455 // the static initializer will initialize at least 25% of array values or there
8456 // is more than 10 items to be initialized
8458 // NOTE: const_initializers_count does not contain default constant values.
8460 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8461 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8462 EmitStaticInitializers (ec, await_stack_field);
8464 if (!only_constant_initializers)
8465 EmitDynamicInitializers (ec, false, await_stack_field);
8469 EmitDynamicInitializers (ec, true, await_stack_field);
8472 if (first_emit_temp != null)
8473 first_emit_temp.Release (ec);
8475 return await_stack_field;
8478 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8480 // no multi dimensional or jagged arrays
8481 if (arguments.Count != 1 || array_element_type.IsArray) {
8482 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8486 // No array covariance, except for array -> object
8487 if (type != targetType) {
8488 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8489 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8493 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8494 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8499 // Single dimensional array of 0 size
8500 if (array_data == null) {
8501 IntConstant ic = arguments[0] as IntConstant;
8502 if (ic == null || !ic.IsDefaultValue) {
8503 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8511 enc.Encode (array_data.Count);
8512 foreach (var element in array_data) {
8513 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8517 protected override void CloneTo (CloneContext clonectx, Expression t)
8519 ArrayCreation target = (ArrayCreation) t;
8521 if (requested_base_type != null)
8522 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8524 if (arguments != null){
8525 target.arguments = new List<Expression> (arguments.Count);
8526 foreach (Expression e in arguments)
8527 target.arguments.Add (e.Clone (clonectx));
8530 if (initializers != null)
8531 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8534 public override object Accept (StructuralVisitor visitor)
8536 return visitor.Visit (this);
8541 // Represents an implicitly typed array epxression
8543 class ImplicitlyTypedArrayCreation : ArrayCreation
8545 TypeInferenceContext best_type_inference;
8547 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8548 : base (null, rank, initializers, loc)
8552 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8553 : base (null, initializers, loc)
8557 protected override Expression DoResolve (ResolveContext ec)
8562 dimensions = rank.Dimension;
8564 best_type_inference = new TypeInferenceContext ();
8566 if (!ResolveInitializers (ec))
8569 best_type_inference.FixAllTypes (ec);
8570 array_element_type = best_type_inference.InferredTypeArguments[0];
8571 best_type_inference = null;
8573 if (array_element_type == null ||
8574 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8575 arguments.Count != rank.Dimension) {
8576 ec.Report.Error (826, loc,
8577 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8582 // At this point we found common base type for all initializer elements
8583 // but we have to be sure that all static initializer elements are of
8586 UnifyInitializerElement (ec);
8588 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8589 eclass = ExprClass.Value;
8594 // Converts static initializer only
8596 void UnifyInitializerElement (ResolveContext ec)
8598 for (int i = 0; i < array_data.Count; ++i) {
8599 Expression e = array_data[i];
8601 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8605 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8607 element = element.Resolve (ec);
8608 if (element != null)
8609 best_type_inference.AddCommonTypeBound (element.Type);
8615 sealed class CompilerGeneratedThis : This
8617 public CompilerGeneratedThis (TypeSpec type, Location loc)
8623 protected override Expression DoResolve (ResolveContext rc)
8625 eclass = ExprClass.Variable;
8627 var block = rc.CurrentBlock;
8628 if (block != null) {
8629 var top = block.ParametersBlock.TopBlock;
8630 if (top.ThisVariable != null)
8631 variable_info = top.ThisVariable.VariableInfo;
8638 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8640 return DoResolve (rc);
8643 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8650 /// Represents the `this' construct
8653 public class This : VariableReference
8655 sealed class ThisVariable : ILocalVariable
8657 public static readonly ILocalVariable Instance = new ThisVariable ();
8659 public void Emit (EmitContext ec)
8664 public void EmitAssign (EmitContext ec)
8666 throw new InvalidOperationException ();
8669 public void EmitAddressOf (EmitContext ec)
8675 protected VariableInfo variable_info;
8677 public This (Location loc)
8684 public override string Name {
8685 get { return "this"; }
8688 public override bool IsLockedByStatement {
8696 public override bool IsRef {
8697 get { return type.IsStruct; }
8700 public override bool IsSideEffectFree {
8706 protected override ILocalVariable Variable {
8707 get { return ThisVariable.Instance; }
8710 public override VariableInfo VariableInfo {
8711 get { return variable_info; }
8714 public override bool IsFixed {
8715 get { return false; }
8720 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8723 // It's null for all cases when we don't need to check `this'
8724 // definitive assignment
8726 if (variable_info == null)
8729 if (fc.IsDefinitelyAssigned (variable_info))
8732 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8735 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8737 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8738 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8739 } else if (ec.CurrentAnonymousMethod != null) {
8740 ec.Report.Error (1673, loc,
8741 "Anonymous methods inside structs cannot access instance members of `this'. " +
8742 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8744 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8748 public override void FlowAnalysis (FlowAnalysisContext fc)
8750 CheckStructThisDefiniteAssignment (fc);
8753 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8758 AnonymousMethodStorey storey = ae.Storey;
8759 return storey != null ? storey.HoistedThis : null;
8762 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8764 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8767 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8770 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8776 public virtual void ResolveBase (ResolveContext ec)
8778 eclass = ExprClass.Variable;
8779 type = ec.CurrentType;
8781 if (!IsThisAvailable (ec, false)) {
8782 Error_ThisNotAvailable (ec);
8786 var block = ec.CurrentBlock;
8787 if (block != null) {
8788 var top = block.ParametersBlock.TopBlock;
8789 if (top.ThisVariable != null)
8790 variable_info = top.ThisVariable.VariableInfo;
8792 AnonymousExpression am = ec.CurrentAnonymousMethod;
8793 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8795 // Hoisted this is almost like hoisted variable but not exactly. When
8796 // there is no variable hoisted we can simply emit an instance method
8797 // without lifting this into a storey. Unfotunatelly this complicates
8798 // things in other cases because we don't know where this will be hoisted
8799 // until top-level block is fully resolved
8801 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8802 am.SetHasThisAccess ();
8807 protected override Expression DoResolve (ResolveContext ec)
8813 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8815 if (eclass == ExprClass.Unresolved)
8819 if (right_side == EmptyExpression.UnaryAddress)
8820 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8821 else if (right_side == EmptyExpression.OutAccess)
8822 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8824 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8830 public override int GetHashCode()
8832 throw new NotImplementedException ();
8835 public override bool Equals (object obj)
8837 This t = obj as This;
8844 protected override void CloneTo (CloneContext clonectx, Expression t)
8849 public override void SetHasAddressTaken ()
8854 public override object Accept (StructuralVisitor visitor)
8856 return visitor.Visit (this);
8861 /// Represents the `__arglist' construct
8863 public class ArglistAccess : Expression
8865 public ArglistAccess (Location loc)
8870 protected override void CloneTo (CloneContext clonectx, Expression target)
8875 public override bool ContainsEmitWithAwait ()
8880 public override Expression CreateExpressionTree (ResolveContext ec)
8882 throw new NotSupportedException ("ET");
8885 protected override Expression DoResolve (ResolveContext ec)
8887 eclass = ExprClass.Variable;
8888 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8890 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8891 ec.Report.Error (190, loc,
8892 "The __arglist construct is valid only within a variable argument method");
8898 public override void Emit (EmitContext ec)
8900 ec.Emit (OpCodes.Arglist);
8903 public override object Accept (StructuralVisitor visitor)
8905 return visitor.Visit (this);
8910 /// Represents the `__arglist (....)' construct
8912 public class Arglist : Expression
8914 Arguments arguments;
8916 public Arglist (Location loc)
8921 public Arglist (Arguments args, Location l)
8927 public Arguments Arguments {
8933 public MetaType[] ArgumentTypes {
8935 if (arguments == null)
8936 return MetaType.EmptyTypes;
8938 var retval = new MetaType[arguments.Count];
8939 for (int i = 0; i < retval.Length; i++)
8940 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8946 public override bool ContainsEmitWithAwait ()
8948 throw new NotImplementedException ();
8951 public override Expression CreateExpressionTree (ResolveContext ec)
8953 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8957 protected override Expression DoResolve (ResolveContext ec)
8959 eclass = ExprClass.Variable;
8960 type = InternalType.Arglist;
8961 if (arguments != null) {
8962 bool dynamic; // Can be ignored as there is always only 1 overload
8963 arguments.Resolve (ec, out dynamic);
8969 public override void Emit (EmitContext ec)
8971 if (arguments != null)
8972 arguments.Emit (ec);
8975 protected override void CloneTo (CloneContext clonectx, Expression t)
8977 Arglist target = (Arglist) t;
8979 if (arguments != null)
8980 target.arguments = arguments.Clone (clonectx);
8983 public override object Accept (StructuralVisitor visitor)
8985 return visitor.Visit (this);
8989 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8991 FullNamedExpression texpr;
8993 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9000 public FullNamedExpression TypeExpression {
9006 public override bool ContainsEmitWithAwait ()
9011 public void AddressOf (EmitContext ec, AddressOp mode)
9014 ec.Emit (OpCodes.Refanyval, type);
9017 protected override Expression DoResolve (ResolveContext rc)
9019 expr = expr.Resolve (rc);
9020 type = texpr.ResolveAsType (rc);
9021 if (expr == null || type == null)
9024 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9025 eclass = ExprClass.Variable;
9029 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9031 return DoResolve (rc);
9034 public override void Emit (EmitContext ec)
9037 ec.Emit (OpCodes.Refanyval, type);
9038 ec.EmitLoadFromPtr (type);
9041 public void Emit (EmitContext ec, bool leave_copy)
9043 throw new NotImplementedException ();
9046 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9049 ec.Emit (OpCodes.Refanyval, type);
9052 LocalTemporary temporary = null;
9054 ec.Emit (OpCodes.Dup);
9055 temporary = new LocalTemporary (source.Type);
9056 temporary.Store (ec);
9059 ec.EmitStoreFromPtr (type);
9061 if (temporary != null) {
9062 temporary.Emit (ec);
9063 temporary.Release (ec);
9067 public override object Accept (StructuralVisitor visitor)
9069 return visitor.Visit (this);
9073 public class RefTypeExpr : ShimExpression
9075 public RefTypeExpr (Expression expr, Location loc)
9081 protected override Expression DoResolve (ResolveContext rc)
9083 expr = expr.Resolve (rc);
9087 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9091 type = rc.BuiltinTypes.Type;
9092 eclass = ExprClass.Value;
9096 public override void Emit (EmitContext ec)
9099 ec.Emit (OpCodes.Refanytype);
9100 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9102 ec.Emit (OpCodes.Call, m);
9105 public override object Accept (StructuralVisitor visitor)
9107 return visitor.Visit (this);
9111 public class MakeRefExpr : ShimExpression
9113 public MakeRefExpr (Expression expr, Location loc)
9119 public override bool ContainsEmitWithAwait ()
9121 throw new NotImplementedException ();
9124 protected override Expression DoResolve (ResolveContext rc)
9126 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9127 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9128 eclass = ExprClass.Value;
9132 public override void Emit (EmitContext ec)
9134 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9135 ec.Emit (OpCodes.Mkrefany, expr.Type);
9138 public override object Accept (StructuralVisitor visitor)
9140 return visitor.Visit (this);
9145 /// Implements the typeof operator
9147 public class TypeOf : Expression {
9148 FullNamedExpression QueriedType;
9151 public TypeOf (FullNamedExpression queried_type, Location l)
9153 QueriedType = queried_type;
9158 // Use this constructor for any compiler generated typeof expression
9160 public TypeOf (TypeSpec type, Location loc)
9162 this.typearg = type;
9168 public override bool IsSideEffectFree {
9174 public TypeSpec TypeArgument {
9180 public FullNamedExpression TypeExpression {
9189 protected override void CloneTo (CloneContext clonectx, Expression t)
9191 TypeOf target = (TypeOf) t;
9192 if (QueriedType != null)
9193 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9196 public override bool ContainsEmitWithAwait ()
9201 public override Expression CreateExpressionTree (ResolveContext ec)
9203 Arguments args = new Arguments (2);
9204 args.Add (new Argument (this));
9205 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9206 return CreateExpressionFactoryCall (ec, "Constant", args);
9209 protected override Expression DoResolve (ResolveContext ec)
9211 if (eclass != ExprClass.Unresolved)
9214 if (typearg == null) {
9216 // Pointer types are allowed without explicit unsafe, they are just tokens
9218 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9219 typearg = QueriedType.ResolveAsType (ec, true);
9222 if (typearg == null)
9225 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9226 ec.Report.Error (1962, QueriedType.Location,
9227 "The typeof operator cannot be used on the dynamic type");
9231 type = ec.BuiltinTypes.Type;
9233 // Even though what is returned is a type object, it's treated as a value by the compiler.
9234 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9235 eclass = ExprClass.Value;
9239 static bool ContainsDynamicType (TypeSpec type)
9241 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9244 var element_container = type as ElementTypeSpec;
9245 if (element_container != null)
9246 return ContainsDynamicType (element_container.Element);
9248 foreach (var t in type.TypeArguments) {
9249 if (ContainsDynamicType (t)) {
9257 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9259 // Target type is not System.Type therefore must be object
9260 // and we need to use different encoding sequence
9261 if (targetType != type)
9264 if (typearg is InflatedTypeSpec) {
9267 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9268 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9269 typearg.GetSignatureForError ());
9273 gt = gt.DeclaringType;
9274 } while (gt != null);
9277 if (ContainsDynamicType (typearg)) {
9278 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9282 enc.EncodeTypeName (typearg);
9285 public override void Emit (EmitContext ec)
9287 ec.Emit (OpCodes.Ldtoken, typearg);
9288 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9290 ec.Emit (OpCodes.Call, m);
9293 public override object Accept (StructuralVisitor visitor)
9295 return visitor.Visit (this);
9299 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9301 public TypeOfMethod (MethodSpec method, Location loc)
9302 : base (method, loc)
9306 protected override Expression DoResolve (ResolveContext ec)
9308 if (member.IsConstructor) {
9309 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9311 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9317 return base.DoResolve (ec);
9320 public override void Emit (EmitContext ec)
9322 ec.Emit (OpCodes.Ldtoken, member);
9325 ec.Emit (OpCodes.Castclass, type);
9328 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9330 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9333 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9335 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9339 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9341 protected readonly T member;
9343 protected TypeOfMember (T member, Location loc)
9345 this.member = member;
9349 public override bool IsSideEffectFree {
9355 public override bool ContainsEmitWithAwait ()
9360 public override Expression CreateExpressionTree (ResolveContext ec)
9362 Arguments args = new Arguments (2);
9363 args.Add (new Argument (this));
9364 args.Add (new Argument (new TypeOf (type, loc)));
9365 return CreateExpressionFactoryCall (ec, "Constant", args);
9368 protected override Expression DoResolve (ResolveContext ec)
9370 eclass = ExprClass.Value;
9374 public override void Emit (EmitContext ec)
9376 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9377 PredefinedMember<MethodSpec> p;
9379 p = GetTypeFromHandleGeneric (ec);
9380 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9382 p = GetTypeFromHandle (ec);
9385 var mi = p.Resolve (loc);
9387 ec.Emit (OpCodes.Call, mi);
9390 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9391 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9394 sealed class TypeOfField : TypeOfMember<FieldSpec>
9396 public TypeOfField (FieldSpec field, Location loc)
9401 protected override Expression DoResolve (ResolveContext ec)
9403 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9407 return base.DoResolve (ec);
9410 public override void Emit (EmitContext ec)
9412 ec.Emit (OpCodes.Ldtoken, member);
9416 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9418 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9421 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9423 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9428 /// Implements the sizeof expression
9430 public class SizeOf : Expression {
9431 readonly Expression texpr;
9432 TypeSpec type_queried;
9434 public SizeOf (Expression queried_type, Location l)
9436 this.texpr = queried_type;
9440 public override bool IsSideEffectFree {
9446 public Expression TypeExpression {
9452 public override bool ContainsEmitWithAwait ()
9457 public override Expression CreateExpressionTree (ResolveContext ec)
9459 Error_PointerInsideExpressionTree (ec);
9463 protected override Expression DoResolve (ResolveContext ec)
9465 type_queried = texpr.ResolveAsType (ec);
9466 if (type_queried == null)
9469 if (type_queried.IsEnum)
9470 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9472 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9474 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9477 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9482 ec.Report.Error (233, loc,
9483 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9484 type_queried.GetSignatureForError ());
9487 type = ec.BuiltinTypes.Int;
9488 eclass = ExprClass.Value;
9492 public override void Emit (EmitContext ec)
9494 ec.Emit (OpCodes.Sizeof, type_queried);
9497 protected override void CloneTo (CloneContext clonectx, Expression t)
9501 public override object Accept (StructuralVisitor visitor)
9503 return visitor.Visit (this);
9508 /// Implements the qualified-alias-member (::) expression.
9510 public class QualifiedAliasMember : MemberAccess
9512 readonly string alias;
9513 public static readonly string GlobalAlias = "global";
9515 public QualifiedAliasMember (string alias, string identifier, Location l)
9516 : base (null, identifier, l)
9521 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9522 : base (null, identifier, targs, l)
9527 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9528 : base (null, identifier, arity, l)
9533 public string Alias {
9539 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9541 if (alias == GlobalAlias)
9542 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9544 int errors = mc.Module.Compiler.Report.Errors;
9545 var expr = mc.LookupNamespaceAlias (alias);
9547 if (errors == mc.Module.Compiler.Report.Errors)
9548 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9556 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9558 expr = CreateExpressionFromAlias (mc);
9562 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9565 protected override Expression DoResolve (ResolveContext rc)
9567 return ResolveAsTypeOrNamespace (rc, false);
9570 public override string GetSignatureForError ()
9573 if (targs != null) {
9574 name = Name + "<" + targs.GetSignatureForError () + ">";
9577 return alias + "::" + name;
9580 public override bool HasConditionalAccess ()
9585 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9587 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9588 rc.Module.Compiler.Report.Error (687, loc,
9589 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9590 GetSignatureForError ());
9595 return DoResolve (rc);
9598 protected override void CloneTo (CloneContext clonectx, Expression t)
9603 public override object Accept (StructuralVisitor visitor)
9605 return visitor.Visit (this);
9610 /// Implements the member access expression
9612 public class MemberAccess : ATypeNameExpression
9614 protected Expression expr;
9616 public MemberAccess (Expression expr, string id)
9617 : base (id, expr.Location)
9622 public MemberAccess (Expression expr, string identifier, Location loc)
9623 : base (identifier, loc)
9628 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9629 : base (identifier, args, loc)
9634 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9635 : base (identifier, arity, loc)
9640 public Expression LeftExpression {
9646 public override Location StartLocation {
9648 return expr == null ? loc : expr.StartLocation;
9652 protected override Expression DoResolve (ResolveContext rc)
9654 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9656 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9661 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9663 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9665 if (e is TypeExpr) {
9666 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9671 e = e.ResolveLValue (rc, rhs);
9676 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9678 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9679 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9681 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9684 public override bool HasConditionalAccess ()
9686 return LeftExpression.HasConditionalAccess ();
9689 public static bool IsValidDotExpression (TypeSpec type)
9691 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9692 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9694 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9697 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9699 var sn = expr as SimpleName;
9700 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9703 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9706 // Resolve expression which does have type set as we need expression type
9707 // with disable flow analysis as we don't know whether left side expression
9708 // is used as variable or type
9710 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9711 expr = expr.Resolve (rc);
9712 } else if (expr is TypeParameterExpr) {
9713 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9717 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9718 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9719 expr = expr.Resolve (rc, flags);
9722 expr = expr.Resolve (rc, flags);
9729 var ns = expr as NamespaceExpression;
9731 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9733 if (retval == null) {
9734 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9739 if (HasTypeArguments)
9740 return new GenericTypeExpr (retval.Type, targs, loc);
9742 targs.Resolve (rc, false);
9748 var cma = this as ConditionalMemberAccess;
9751 TypeSpec expr_type = expr.Type;
9752 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9753 me = expr as MemberExpr;
9755 me.ResolveInstanceExpression (rc, null);
9757 Arguments args = new Arguments (1);
9758 args.Add (new Argument (expr));
9761 return new DynamicConditionalMemberBinder (Name, args, loc);
9763 return new DynamicMemberBinder (Name, args, loc);
9767 if (!IsNullPropagatingValid (expr.Type)) {
9768 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9772 if (expr_type.IsNullableType) {
9773 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9774 expr_type = expr.Type;
9778 if (!IsValidDotExpression (expr_type)) {
9779 Error_OperatorCannotBeApplied (rc, expr_type);
9783 var lookup_arity = Arity;
9784 bool errorMode = false;
9785 Expression member_lookup;
9787 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9788 if (member_lookup == null) {
9790 // Try to look for extension method when member lookup failed
9792 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9793 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9794 if (methods != null) {
9795 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9796 if (HasTypeArguments) {
9797 if (!targs.Resolve (rc, false))
9800 emg.SetTypeArguments (rc, targs);
9804 emg.ConditionalAccess = true;
9806 // TODO: it should really skip the checks bellow
9807 return emg.Resolve (rc);
9813 if (member_lookup == null) {
9814 var dep = expr_type.GetMissingDependencies ();
9816 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9817 } else if (expr is TypeExpr) {
9818 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9820 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9826 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9827 // Leave it to overload resolution to report correct error
9828 } else if (!(member_lookup is TypeExpr)) {
9829 // TODO: rc.SymbolRelatedToPreviousError
9830 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9835 if (member_lookup != null)
9839 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9843 TypeExpr texpr = member_lookup as TypeExpr;
9844 if (texpr != null) {
9845 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9846 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9847 Name, texpr.GetSignatureForError ());
9850 if (!texpr.Type.IsAccessible (rc)) {
9851 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9852 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9856 if (HasTypeArguments) {
9857 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9860 return member_lookup;
9863 me = member_lookup as MemberExpr;
9865 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9870 me.ConditionalAccess = true;
9873 me = me.ResolveMemberAccess (rc, expr, sn);
9876 if (!targs.Resolve (rc, false))
9879 me.SetTypeArguments (rc, targs);
9885 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9887 FullNamedExpression fexpr = expr as FullNamedExpression;
9888 if (fexpr == null) {
9889 expr.ResolveAsType (rc);
9893 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9895 if (expr_resolved == null)
9898 var ns = expr_resolved as NamespaceExpression;
9900 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9902 if (retval == null) {
9903 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9904 } else if (Arity > 0) {
9905 if (HasTypeArguments) {
9906 retval = new GenericTypeExpr (retval.Type, targs, loc);
9907 if (retval.ResolveAsType (rc) == null)
9910 targs.Resolve (rc, allowUnboundTypeArguments);
9912 retval = new GenericOpenTypeExpr (retval.Type, loc);
9919 var tnew_expr = expr_resolved.ResolveAsType (rc);
9920 if (tnew_expr == null)
9923 TypeSpec expr_type = tnew_expr;
9924 if (TypeManager.IsGenericParameter (expr_type)) {
9925 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9926 tnew_expr.GetSignatureForError ());
9930 var qam = this as QualifiedAliasMember;
9932 rc.Module.Compiler.Report.Error (431, loc,
9933 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9938 TypeSpec nested = null;
9939 while (expr_type != null) {
9940 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9941 if (nested == null) {
9942 if (expr_type == tnew_expr) {
9943 Error_IdentifierNotFound (rc, expr_type);
9947 expr_type = tnew_expr;
9948 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9949 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9953 if (nested.IsAccessible (rc))
9957 // Keep looking after inaccessible candidate but only if
9958 // we are not in same context as the definition itself
9960 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9963 expr_type = expr_type.BaseType;
9968 if (HasTypeArguments) {
9969 texpr = new GenericTypeExpr (nested, targs, loc);
9971 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9973 texpr = new GenericOpenTypeExpr (nested, loc);
9975 } else if (expr_resolved is GenericOpenTypeExpr) {
9976 texpr = new GenericOpenTypeExpr (nested, loc);
9978 texpr = new TypeExpression (nested, loc);
9981 if (texpr.ResolveAsType (rc) == null)
9987 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9989 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9991 if (nested != null) {
9992 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9996 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9997 if (any_other_member != null) {
9998 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10002 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10003 Name, expr_type.GetSignatureForError ());
10006 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10008 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10011 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10013 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10014 ec.Report.SymbolRelatedToPreviousError (type);
10016 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10018 // a using directive or an assembly reference
10019 if (cand != null) {
10020 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10022 missing = "an assembly reference";
10025 ec.Report.Error (1061, loc,
10026 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10027 type.GetSignatureForError (), name, missing);
10031 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10034 public override string GetSignatureForError ()
10036 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10039 protected override void CloneTo (CloneContext clonectx, Expression t)
10041 MemberAccess target = (MemberAccess) t;
10043 target.expr = expr.Clone (clonectx);
10046 public override object Accept (StructuralVisitor visitor)
10048 return visitor.Visit (this);
10052 public class ConditionalMemberAccess : MemberAccess
10054 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10055 : base (expr, identifier, args, loc)
10059 public override bool HasConditionalAccess ()
10066 /// Implements checked expressions
10068 public class CheckedExpr : Expression {
10070 public Expression Expr;
10072 public CheckedExpr (Expression e, Location l)
10078 public override bool ContainsEmitWithAwait ()
10080 return Expr.ContainsEmitWithAwait ();
10083 public override Expression CreateExpressionTree (ResolveContext ec)
10085 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10086 return Expr.CreateExpressionTree (ec);
10089 protected override Expression DoResolve (ResolveContext ec)
10091 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10092 Expr = Expr.Resolve (ec);
10097 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10100 eclass = Expr.eclass;
10105 public override void Emit (EmitContext ec)
10107 using (ec.With (EmitContext.Options.CheckedScope, true))
10111 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10113 using (ec.With (EmitContext.Options.CheckedScope, true))
10114 Expr.EmitBranchable (ec, target, on_true);
10117 public override void FlowAnalysis (FlowAnalysisContext fc)
10119 Expr.FlowAnalysis (fc);
10122 public override SLE.Expression MakeExpression (BuilderContext ctx)
10124 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10125 return Expr.MakeExpression (ctx);
10129 protected override void CloneTo (CloneContext clonectx, Expression t)
10131 CheckedExpr target = (CheckedExpr) t;
10133 target.Expr = Expr.Clone (clonectx);
10136 public override object Accept (StructuralVisitor visitor)
10138 return visitor.Visit (this);
10143 /// Implements the unchecked expression
10145 public class UnCheckedExpr : Expression {
10147 public Expression Expr;
10149 public UnCheckedExpr (Expression e, Location l)
10155 public override bool ContainsEmitWithAwait ()
10157 return Expr.ContainsEmitWithAwait ();
10160 public override Expression CreateExpressionTree (ResolveContext ec)
10162 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10163 return Expr.CreateExpressionTree (ec);
10166 protected override Expression DoResolve (ResolveContext ec)
10168 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10169 Expr = Expr.Resolve (ec);
10174 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10177 eclass = Expr.eclass;
10182 public override void Emit (EmitContext ec)
10184 using (ec.With (EmitContext.Options.CheckedScope, false))
10188 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10190 using (ec.With (EmitContext.Options.CheckedScope, false))
10191 Expr.EmitBranchable (ec, target, on_true);
10194 public override void FlowAnalysis (FlowAnalysisContext fc)
10196 Expr.FlowAnalysis (fc);
10199 protected override void CloneTo (CloneContext clonectx, Expression t)
10201 UnCheckedExpr target = (UnCheckedExpr) t;
10203 target.Expr = Expr.Clone (clonectx);
10206 public override object Accept (StructuralVisitor visitor)
10208 return visitor.Visit (this);
10213 /// An Element Access expression.
10215 /// During semantic analysis these are transformed into
10216 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10218 public class ElementAccess : Expression
10220 public Arguments Arguments;
10221 public Expression Expr;
10222 bool conditional_access_receiver;
10224 public ElementAccess (Expression e, Arguments args, Location loc)
10228 this.Arguments = args;
10231 public bool ConditionalAccess { get; set; }
10233 public override Location StartLocation {
10235 return Expr.StartLocation;
10239 public override bool ContainsEmitWithAwait ()
10241 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10245 // We perform some simple tests, and then to "split" the emit and store
10246 // code we create an instance of a different class, and return that.
10248 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10250 if (conditionalAccessReceiver)
10251 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10253 Expr = Expr.Resolve (ec);
10255 if (conditionalAccessReceiver)
10256 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10263 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10264 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10268 if (type.IsArray) {
10269 var aa = new ArrayAccess (this, loc) {
10270 ConditionalAccess = ConditionalAccess,
10273 if (conditionalAccessReceiver)
10274 aa.SetConditionalAccessReceiver ();
10279 if (type.IsPointer)
10280 return Expr.MakePointerAccess (ec, type, Arguments);
10282 FieldExpr fe = Expr as FieldExpr;
10284 var ff = fe.Spec as FixedFieldSpec;
10286 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10290 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10291 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10292 var indexer = new IndexerExpr (indexers, type, this) {
10293 ConditionalAccess = ConditionalAccess
10296 if (conditionalAccessReceiver)
10297 indexer.SetConditionalAccessReceiver ();
10302 Error_CannotApplyIndexing (ec, type, loc);
10307 public override Expression CreateExpressionTree (ResolveContext ec)
10309 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10310 Expr.CreateExpressionTree (ec));
10312 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10315 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10317 if (type != InternalType.ErrorType) {
10318 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10319 type.GetSignatureForError ());
10323 public override bool HasConditionalAccess ()
10325 return ConditionalAccess || Expr.HasConditionalAccess ();
10328 void ResolveConditionalAccessReceiver (ResolveContext rc)
10330 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10331 conditional_access_receiver = true;
10335 protected override Expression DoResolve (ResolveContext rc)
10337 ResolveConditionalAccessReceiver (rc);
10339 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10343 return expr.Resolve (rc);
10346 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10348 var res = CreateAccessExpression (ec, false);
10352 return res.ResolveLValue (ec, rhs);
10355 public override void Emit (EmitContext ec)
10357 throw new Exception ("Should never be reached");
10360 public override void FlowAnalysis (FlowAnalysisContext fc)
10362 Expr.FlowAnalysis (fc);
10364 Arguments.FlowAnalysis (fc);
10367 public override string GetSignatureForError ()
10369 return Expr.GetSignatureForError ();
10372 protected override void CloneTo (CloneContext clonectx, Expression t)
10374 ElementAccess target = (ElementAccess) t;
10376 target.Expr = Expr.Clone (clonectx);
10377 if (Arguments != null)
10378 target.Arguments = Arguments.Clone (clonectx);
10381 public override object Accept (StructuralVisitor visitor)
10383 return visitor.Visit (this);
10388 /// Implements array access
10390 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10392 // Points to our "data" repository
10396 LocalTemporary temp;
10398 bool? has_await_args;
10399 bool conditional_access_receiver;
10401 public ArrayAccess (ElementAccess ea_data, Location l)
10407 public bool ConditionalAccess { get; set; }
10409 public void AddressOf (EmitContext ec, AddressOp mode)
10411 var ac = (ArrayContainer) ea.Expr.Type;
10413 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10414 LoadInstanceAndArguments (ec, false, true);
10417 LoadInstanceAndArguments (ec, false, false);
10419 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10420 ec.Emit (OpCodes.Readonly);
10422 ec.EmitArrayAddress (ac);
10425 public override Expression CreateExpressionTree (ResolveContext ec)
10427 if (ConditionalAccess)
10428 Error_NullShortCircuitInsideExpressionTree (ec);
10430 return ea.CreateExpressionTree (ec);
10433 public override bool ContainsEmitWithAwait ()
10435 return ea.ContainsEmitWithAwait ();
10438 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10440 if (HasConditionalAccess ())
10441 Error_NullPropagatingLValue (ec);
10443 return DoResolve (ec);
10446 protected override Expression DoResolve (ResolveContext ec)
10448 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10450 ea.Arguments.Resolve (ec, out dynamic);
10452 var ac = ea.Expr.Type as ArrayContainer;
10453 int rank = ea.Arguments.Count;
10454 if (ac.Rank != rank) {
10455 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10456 rank.ToString (), ac.Rank.ToString ());
10461 if (type.IsPointer && !ec.IsUnsafe) {
10462 UnsafeError (ec, ea.Location);
10465 if (conditional_access_receiver)
10466 type = LiftMemberType (ec, type);
10468 foreach (Argument a in ea.Arguments) {
10469 var na = a as NamedArgument;
10471 ElementAccess.Error_NamedArgument (na, ec.Report);
10473 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10476 eclass = ExprClass.Variable;
10481 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10483 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10486 public override void FlowAnalysis (FlowAnalysisContext fc)
10488 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10490 ea.FlowAnalysis (fc);
10492 if (conditional_access_receiver)
10493 fc.DefiniteAssignment = da;
10496 public override bool HasConditionalAccess ()
10498 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10502 // Load the array arguments into the stack.
10504 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10506 if (prepareAwait) {
10507 ea.Expr = ea.Expr.EmitToField (ec);
10509 var ie = new InstanceEmitter (ea.Expr, false);
10510 ie.Emit (ec, ConditionalAccess);
10512 if (duplicateArguments) {
10513 ec.Emit (OpCodes.Dup);
10515 var copy = new LocalTemporary (ea.Expr.Type);
10521 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10522 if (dup_args != null)
10523 ea.Arguments = dup_args;
10526 public void Emit (EmitContext ec, bool leave_copy)
10529 ec.EmitLoadFromPtr (type);
10531 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10532 LoadInstanceAndArguments (ec, false, true);
10535 if (conditional_access_receiver)
10536 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10538 var ac = (ArrayContainer) ea.Expr.Type;
10539 LoadInstanceAndArguments (ec, false, false);
10540 ec.EmitArrayLoad (ac);
10542 if (conditional_access_receiver)
10543 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10547 ec.Emit (OpCodes.Dup);
10548 temp = new LocalTemporary (this.type);
10553 public override void Emit (EmitContext ec)
10558 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10560 var ac = (ArrayContainer) ea.Expr.Type;
10561 TypeSpec t = source.Type;
10563 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10566 // When we are dealing with a struct, get the address of it to avoid value copy
10567 // Same cannot be done for reference type because array covariance and the
10568 // check in ldelema requires to specify the type of array element stored at the index
10570 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10571 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10573 if (has_await_args.Value) {
10574 if (source.ContainsEmitWithAwait ()) {
10575 source = source.EmitToField (ec);
10576 isCompound = false;
10580 LoadInstanceAndArguments (ec, isCompound, false);
10585 ec.EmitArrayAddress (ac);
10588 ec.Emit (OpCodes.Dup);
10592 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10594 if (has_await_args.Value) {
10595 if (source.ContainsEmitWithAwait ())
10596 source = source.EmitToField (ec);
10598 LoadInstanceAndArguments (ec, false, false);
10605 var lt = ea.Expr as LocalTemporary;
10611 ec.Emit (OpCodes.Dup);
10612 temp = new LocalTemporary (this.type);
10617 ec.EmitStoreFromPtr (t);
10619 ec.EmitArrayStore (ac);
10622 if (temp != null) {
10628 public override Expression EmitToField (EmitContext ec)
10631 // Have to be specialized for arrays to get access to
10632 // underlying element. Instead of another result copy we
10633 // need direct access to element
10637 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10639 ea.Expr = ea.Expr.EmitToField (ec);
10640 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10644 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10646 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10649 public override SLE.Expression MakeExpression (BuilderContext ctx)
10651 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10654 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10656 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10657 return Arguments.MakeExpression (ea.Arguments, ctx);
10661 public void SetConditionalAccessReceiver ()
10663 conditional_access_receiver = true;
10668 // Indexer access expression
10670 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10672 IList<MemberSpec> indexers;
10673 Arguments arguments;
10674 TypeSpec queried_type;
10676 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10677 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10681 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10684 this.indexers = indexers;
10685 this.queried_type = queriedType;
10686 this.InstanceExpression = instance;
10687 this.arguments = args;
10692 protected override Arguments Arguments {
10701 protected override TypeSpec DeclaringType {
10703 return best_candidate.DeclaringType;
10707 public override bool IsInstance {
10713 public override bool IsStatic {
10719 public override string KindName {
10720 get { return "indexer"; }
10723 public override string Name {
10731 public override bool ContainsEmitWithAwait ()
10733 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10736 public override Expression CreateExpressionTree (ResolveContext ec)
10738 if (ConditionalAccess) {
10739 Error_NullShortCircuitInsideExpressionTree (ec);
10742 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10743 InstanceExpression.CreateExpressionTree (ec),
10744 new TypeOfMethod (Getter, loc));
10746 return CreateExpressionFactoryCall (ec, "Call", args);
10749 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10751 LocalTemporary await_source_arg = null;
10754 emitting_compound_assignment = true;
10755 if (source is DynamicExpressionStatement) {
10760 emitting_compound_assignment = false;
10762 if (has_await_arguments) {
10763 await_source_arg = new LocalTemporary (Type);
10764 await_source_arg.Store (ec);
10766 arguments.Add (new Argument (await_source_arg));
10769 temp = await_source_arg;
10772 has_await_arguments = false;
10777 ec.Emit (OpCodes.Dup);
10778 temp = new LocalTemporary (Type);
10784 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10785 source = source.EmitToField (ec);
10787 temp = new LocalTemporary (Type);
10794 arguments.Add (new Argument (source));
10797 var call = new CallEmitter ();
10798 call.InstanceExpression = InstanceExpression;
10799 if (arguments == null)
10800 call.InstanceExpressionOnStack = true;
10802 call.Emit (ec, Setter, arguments, loc);
10804 if (temp != null) {
10807 } else if (leave_copy) {
10811 if (await_source_arg != null) {
10812 await_source_arg.Release (ec);
10816 public override void FlowAnalysis (FlowAnalysisContext fc)
10818 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10820 base.FlowAnalysis (fc);
10821 arguments.FlowAnalysis (fc);
10823 if (conditional_access_receiver)
10824 fc.DefiniteAssignment = da;
10827 public override string GetSignatureForError ()
10829 return best_candidate.GetSignatureForError ();
10832 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10835 throw new NotSupportedException ();
10837 var value = new[] { source.MakeExpression (ctx) };
10838 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10839 return SLE.Expression.Block (
10840 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10845 public override SLE.Expression MakeExpression (BuilderContext ctx)
10848 return base.MakeExpression (ctx);
10850 var args = Arguments.MakeExpression (arguments, ctx);
10851 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10855 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10857 if (best_candidate != null)
10860 eclass = ExprClass.IndexerAccess;
10863 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10864 arguments.Resolve (rc, out dynamic);
10867 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10870 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10871 res.BaseMembersProvider = this;
10872 res.InstanceQualifier = this;
10874 // TODO: Do I need 2 argument sets?
10875 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10876 if (best_candidate != null)
10877 type = res.BestCandidateReturnType;
10878 else if (!res.BestCandidateIsDynamic)
10883 // It has dynamic arguments
10886 Arguments args = new Arguments (arguments.Count + 1);
10888 rc.Report.Error (1972, loc,
10889 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10891 args.Add (new Argument (InstanceExpression));
10893 args.AddRange (arguments);
10895 best_candidate = null;
10896 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10900 // Try to avoid resolving left expression again
10902 if (right_side != null)
10903 ResolveInstanceExpression (rc, right_side);
10908 protected override void CloneTo (CloneContext clonectx, Expression t)
10910 IndexerExpr target = (IndexerExpr) t;
10912 if (arguments != null)
10913 target.arguments = arguments.Clone (clonectx);
10916 public void SetConditionalAccessReceiver ()
10918 conditional_access_receiver = true;
10921 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10923 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10926 #region IBaseMembersProvider Members
10928 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10930 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10933 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10935 if (queried_type == member.DeclaringType)
10938 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10939 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10942 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10951 // A base access expression
10953 public class BaseThis : This
10955 public BaseThis (Location loc)
10960 public BaseThis (TypeSpec type, Location loc)
10964 eclass = ExprClass.Variable;
10969 public override string Name {
10977 public override Expression CreateExpressionTree (ResolveContext ec)
10979 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10980 return base.CreateExpressionTree (ec);
10983 public override void Emit (EmitContext ec)
10987 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10988 var context_type = ec.CurrentType;
10989 ec.Emit (OpCodes.Ldobj, context_type);
10990 ec.Emit (OpCodes.Box, context_type);
10994 protected override void Error_ThisNotAvailable (ResolveContext ec)
10997 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10999 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11003 public override void ResolveBase (ResolveContext ec)
11005 base.ResolveBase (ec);
11006 type = ec.CurrentType.BaseType;
11009 public override object Accept (StructuralVisitor visitor)
11011 return visitor.Visit (this);
11016 /// This class exists solely to pass the Type around and to be a dummy
11017 /// that can be passed to the conversion functions (this is used by
11018 /// foreach implementation to typecast the object return value from
11019 /// get_Current into the proper type. All code has been generated and
11020 /// we only care about the side effect conversions to be performed
11022 /// This is also now used as a placeholder where a no-action expression
11023 /// is needed (the `New' class).
11025 public class EmptyExpression : Expression
11027 sealed class OutAccessExpression : EmptyExpression
11029 public OutAccessExpression (TypeSpec t)
11034 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11036 rc.Report.Error (206, right_side.Location,
11037 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11043 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11044 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11045 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11046 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11047 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11048 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11049 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11050 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11052 public EmptyExpression (TypeSpec t)
11055 eclass = ExprClass.Value;
11056 loc = Location.Null;
11059 protected override void CloneTo (CloneContext clonectx, Expression target)
11063 public override bool ContainsEmitWithAwait ()
11068 public override Expression CreateExpressionTree (ResolveContext ec)
11070 throw new NotSupportedException ("ET");
11073 protected override Expression DoResolve (ResolveContext ec)
11078 public override void Emit (EmitContext ec)
11080 // nothing, as we only exist to not do anything.
11083 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11087 public override void EmitSideEffect (EmitContext ec)
11091 public override object Accept (StructuralVisitor visitor)
11093 return visitor.Visit (this);
11097 sealed class EmptyAwaitExpression : EmptyExpression
11099 public EmptyAwaitExpression (TypeSpec type)
11104 public override bool ContainsEmitWithAwait ()
11111 // Empty statement expression
11113 public sealed class EmptyExpressionStatement : ExpressionStatement
11115 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11117 private EmptyExpressionStatement ()
11119 loc = Location.Null;
11122 public override bool ContainsEmitWithAwait ()
11127 public override Expression CreateExpressionTree (ResolveContext ec)
11132 public override void EmitStatement (EmitContext ec)
11137 protected override Expression DoResolve (ResolveContext ec)
11139 eclass = ExprClass.Value;
11140 type = ec.BuiltinTypes.Object;
11144 public override void Emit (EmitContext ec)
11149 public override object Accept (StructuralVisitor visitor)
11151 return visitor.Visit (this);
11155 public class ErrorExpression : EmptyExpression
11157 public static readonly ErrorExpression Instance = new ErrorExpression ();
11159 private ErrorExpression ()
11160 : base (InternalType.ErrorType)
11164 public override Expression CreateExpressionTree (ResolveContext ec)
11169 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11174 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11178 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11182 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11186 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11190 public override object Accept (StructuralVisitor visitor)
11192 return visitor.Visit (this);
11196 public class UserCast : Expression {
11200 public UserCast (MethodSpec method, Expression source, Location l)
11202 if (source == null)
11203 throw new ArgumentNullException ("source");
11205 this.method = method;
11206 this.source = source;
11207 type = method.ReturnType;
11211 public Expression Source {
11220 public override bool ContainsEmitWithAwait ()
11222 return source.ContainsEmitWithAwait ();
11225 public override Expression CreateExpressionTree (ResolveContext ec)
11227 Arguments args = new Arguments (3);
11228 args.Add (new Argument (source.CreateExpressionTree (ec)));
11229 args.Add (new Argument (new TypeOf (type, loc)));
11230 args.Add (new Argument (new TypeOfMethod (method, loc)));
11231 return CreateExpressionFactoryCall (ec, "Convert", args);
11234 protected override Expression DoResolve (ResolveContext ec)
11236 method.CheckObsoleteness (ec, source.Location);
11238 eclass = ExprClass.Value;
11242 public override void Emit (EmitContext ec)
11245 ec.MarkCallEntry (loc);
11246 ec.Emit (OpCodes.Call, method);
11249 public override void FlowAnalysis (FlowAnalysisContext fc)
11251 source.FlowAnalysis (fc);
11254 public override string GetSignatureForError ()
11256 return TypeManager.CSharpSignature (method);
11259 public override SLE.Expression MakeExpression (BuilderContext ctx)
11262 return base.MakeExpression (ctx);
11264 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11270 // Holds additional type specifiers like ?, *, []
11272 public class ComposedTypeSpecifier
11274 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11276 public readonly int Dimension;
11277 public readonly Location Location;
11279 public ComposedTypeSpecifier (int specifier, Location loc)
11281 this.Dimension = specifier;
11282 this.Location = loc;
11286 public bool IsNullable {
11288 return Dimension == -1;
11292 public bool IsPointer {
11294 return Dimension == -2;
11298 public ComposedTypeSpecifier Next { get; set; }
11302 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11304 return new ComposedTypeSpecifier (dimension, loc);
11307 public static ComposedTypeSpecifier CreateNullable (Location loc)
11309 return new ComposedTypeSpecifier (-1, loc);
11312 public static ComposedTypeSpecifier CreatePointer (Location loc)
11314 return new ComposedTypeSpecifier (-2, loc);
11317 public string GetSignatureForError ()
11322 ArrayContainer.GetPostfixSignature (Dimension);
11324 return Next != null ? s + Next.GetSignatureForError () : s;
11329 // This class is used to "construct" the type during a typecast
11330 // operation. Since the Type.GetType class in .NET can parse
11331 // the type specification, we just use this to construct the type
11332 // one bit at a time.
11334 public class ComposedCast : TypeExpr {
11335 FullNamedExpression left;
11336 ComposedTypeSpecifier spec;
11338 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11341 throw new ArgumentNullException ("spec");
11345 this.loc = left.Location;
11348 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11350 type = left.ResolveAsType (ec);
11354 eclass = ExprClass.Type;
11356 var single_spec = spec;
11358 if (single_spec.IsNullable) {
11359 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11363 single_spec = single_spec.Next;
11364 } else if (single_spec.IsPointer) {
11366 // Declared fields cannot have unmanaged check done before all types are defined
11368 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11371 if (!ec.IsUnsafe) {
11372 UnsafeError (ec.Module.Compiler.Report, loc);
11376 type = PointerContainer.MakeType (ec.Module, type);
11377 single_spec = single_spec.Next;
11378 } while (single_spec != null && single_spec.IsPointer);
11381 if (single_spec != null && single_spec.Dimension > 0) {
11382 if (type.IsSpecialRuntimeType) {
11383 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11384 } else if (type.IsStatic) {
11385 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11386 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11387 type.GetSignatureForError ());
11389 MakeArray (ec.Module, single_spec);
11396 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11398 if (spec.Next != null)
11399 MakeArray (module, spec.Next);
11401 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11404 public override string GetSignatureForError ()
11406 return left.GetSignatureForError () + spec.GetSignatureForError ();
11409 public override object Accept (StructuralVisitor visitor)
11411 return visitor.Visit (this);
11415 class FixedBufferPtr : Expression
11417 readonly Expression array;
11419 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11421 this.type = array_type;
11422 this.array = array;
11426 public override bool ContainsEmitWithAwait ()
11428 throw new NotImplementedException ();
11431 public override Expression CreateExpressionTree (ResolveContext ec)
11433 Error_PointerInsideExpressionTree (ec);
11437 public override void Emit(EmitContext ec)
11442 protected override Expression DoResolve (ResolveContext ec)
11444 type = PointerContainer.MakeType (ec.Module, type);
11445 eclass = ExprClass.Value;
11452 // This class is used to represent the address of an array, used
11453 // only by the Fixed statement, this generates "&a [0]" construct
11454 // for fixed (char *pa = a)
11456 class ArrayPtr : FixedBufferPtr
11458 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11459 base (array, array_type, l)
11463 public override void Emit (EmitContext ec)
11468 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11473 // Encapsulates a conversion rules required for array indexes
11475 public class ArrayIndexCast : TypeCast
11477 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11478 : base (expr, returnType)
11480 if (expr.Type == returnType) // int -> int
11481 throw new ArgumentException ("unnecessary array index conversion");
11484 public override Expression CreateExpressionTree (ResolveContext ec)
11486 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11487 return base.CreateExpressionTree (ec);
11491 public override void Emit (EmitContext ec)
11495 switch (child.Type.BuiltinType) {
11496 case BuiltinTypeSpec.Type.UInt:
11497 ec.Emit (OpCodes.Conv_U);
11499 case BuiltinTypeSpec.Type.Long:
11500 ec.Emit (OpCodes.Conv_Ovf_I);
11502 case BuiltinTypeSpec.Type.ULong:
11503 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11506 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11512 // Implements the `stackalloc' keyword
11514 public class StackAlloc : Expression {
11519 public StackAlloc (Expression type, Expression count, Location l)
11522 this.count = count;
11526 public Expression TypeExpression {
11532 public Expression CountExpression {
11538 public override bool ContainsEmitWithAwait ()
11543 public override Expression CreateExpressionTree (ResolveContext ec)
11545 throw new NotSupportedException ("ET");
11548 protected override Expression DoResolve (ResolveContext ec)
11550 count = count.Resolve (ec);
11554 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11555 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11560 Constant c = count as Constant;
11561 if (c != null && c.IsNegative) {
11562 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11565 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11566 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11569 otype = texpr.ResolveAsType (ec);
11573 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11576 type = PointerContainer.MakeType (ec.Module, otype);
11577 eclass = ExprClass.Value;
11582 public override void Emit (EmitContext ec)
11584 int size = BuiltinTypeSpec.GetSize (otype);
11589 ec.Emit (OpCodes.Sizeof, otype);
11593 ec.Emit (OpCodes.Mul_Ovf_Un);
11594 ec.Emit (OpCodes.Localloc);
11597 protected override void CloneTo (CloneContext clonectx, Expression t)
11599 StackAlloc target = (StackAlloc) t;
11600 target.count = count.Clone (clonectx);
11601 target.texpr = texpr.Clone (clonectx);
11604 public override object Accept (StructuralVisitor visitor)
11606 return visitor.Visit (this);
11611 // An object initializer expression
11613 public class ElementInitializer : Assign
11615 public readonly string Name;
11617 public ElementInitializer (string name, Expression initializer, Location loc)
11618 : base (null, initializer, loc)
11623 public bool IsDictionaryInitializer {
11625 return Name == null;
11629 protected override void CloneTo (CloneContext clonectx, Expression t)
11631 ElementInitializer target = (ElementInitializer) t;
11632 target.source = source.Clone (clonectx);
11635 public override Expression CreateExpressionTree (ResolveContext ec)
11637 Arguments args = new Arguments (2);
11638 FieldExpr fe = target as FieldExpr;
11640 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11642 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11645 Expression arg_expr;
11646 var cinit = source as CollectionOrObjectInitializers;
11647 if (cinit == null) {
11649 arg_expr = source.CreateExpressionTree (ec);
11651 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11652 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11655 args.Add (new Argument (arg_expr));
11656 return CreateExpressionFactoryCall (ec, mname, args);
11659 protected override Expression DoResolve (ResolveContext ec)
11661 if (source == null)
11662 return EmptyExpressionStatement.Instance;
11664 if (!ResolveElement (ec))
11667 if (source is CollectionOrObjectInitializers) {
11668 target = target.Resolve (ec);
11669 if (target == null)
11672 Expression previous = ec.CurrentInitializerVariable;
11673 ec.CurrentInitializerVariable = target;
11674 source = source.Resolve (ec);
11675 ec.CurrentInitializerVariable = previous;
11676 if (source == null)
11679 eclass = source.eclass;
11680 type = source.Type;
11685 return base.DoResolve (ec);
11688 public override void EmitStatement (EmitContext ec)
11690 if (source is CollectionOrObjectInitializers)
11693 base.EmitStatement (ec);
11696 protected virtual bool ResolveElement (ResolveContext rc)
11698 var t = rc.CurrentInitializerVariable.Type;
11699 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11700 Arguments args = new Arguments (1);
11701 args.Add (new Argument (rc.CurrentInitializerVariable));
11702 target = new DynamicMemberBinder (Name, args, loc);
11704 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11705 if (member == null) {
11706 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11708 if (member != null) {
11709 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11710 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11715 if (member == null) {
11716 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11720 var me = member as MemberExpr;
11721 if (me is EventExpr) {
11722 me = me.ResolveMemberAccess (rc, null, null);
11723 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11724 rc.Report.Error (1913, loc,
11725 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11726 member.GetSignatureForError ());
11732 rc.Report.Error (1914, loc,
11733 "Static field or property `{0}' cannot be assigned in an object initializer",
11734 me.GetSignatureForError ());
11738 me.InstanceExpression = rc.CurrentInitializerVariable;
11746 // A collection initializer expression
11748 class CollectionElementInitializer : Invocation
11750 public class ElementInitializerArgument : Argument
11752 public ElementInitializerArgument (Expression e)
11758 sealed class AddMemberAccess : MemberAccess
11760 public AddMemberAccess (Expression expr, Location loc)
11761 : base (expr, "Add", loc)
11765 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11767 if (TypeManager.HasElementType (type))
11770 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11774 public CollectionElementInitializer (Expression argument)
11775 : base (null, new Arguments (1))
11777 base.arguments.Add (new ElementInitializerArgument (argument));
11778 this.loc = argument.Location;
11781 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11782 : base (null, new Arguments (arguments.Count))
11784 foreach (Expression e in arguments)
11785 base.arguments.Add (new ElementInitializerArgument (e));
11790 public CollectionElementInitializer (Location loc)
11791 : base (null, null)
11796 public override Expression CreateExpressionTree (ResolveContext ec)
11798 Arguments args = new Arguments (2);
11799 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11801 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11802 foreach (Argument a in arguments) {
11803 if (a.ArgType == Argument.AType.ExtensionType) {
11804 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11807 expr_initializers.Add (a.CreateExpressionTree (ec));
11810 args.Add (new Argument (new ArrayCreation (
11811 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11812 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11815 protected override void CloneTo (CloneContext clonectx, Expression t)
11817 CollectionElementInitializer target = (CollectionElementInitializer) t;
11818 if (arguments != null)
11819 target.arguments = arguments.Clone (clonectx);
11822 protected override Expression DoResolve (ResolveContext ec)
11824 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11826 return base.DoResolve (ec);
11830 class DictionaryElementInitializer : ElementInitializer
11832 readonly Arguments args;
11834 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11835 : base (null, initializer, loc)
11837 this.args = arguments;
11840 public override Expression CreateExpressionTree (ResolveContext ec)
11842 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11846 protected override bool ResolveElement (ResolveContext rc)
11848 var init = rc.CurrentInitializerVariable;
11849 var type = init.Type;
11851 if (type.IsArray) {
11852 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11856 if (type.IsPointer) {
11857 target = init.MakePointerAccess (rc, type, args);
11861 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11862 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11863 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11867 target = new IndexerExpr (indexers, type, init, args, loc);
11873 // A block of object or collection initializers
11875 public class CollectionOrObjectInitializers : ExpressionStatement
11877 IList<Expression> initializers;
11878 bool is_collection_initialization;
11880 public CollectionOrObjectInitializers (Location loc)
11881 : this (new Expression[0], loc)
11885 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11887 this.initializers = initializers;
11891 public IList<Expression> Initializers {
11893 return initializers;
11897 public bool IsEmpty {
11899 return initializers.Count == 0;
11903 public bool IsCollectionInitializer {
11905 return is_collection_initialization;
11909 protected override void CloneTo (CloneContext clonectx, Expression target)
11911 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11913 t.initializers = new List<Expression> (initializers.Count);
11914 foreach (var e in initializers)
11915 t.initializers.Add (e.Clone (clonectx));
11918 public override bool ContainsEmitWithAwait ()
11920 foreach (var e in initializers) {
11921 if (e.ContainsEmitWithAwait ())
11928 public override Expression CreateExpressionTree (ResolveContext ec)
11930 return CreateExpressionTree (ec, false);
11933 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11935 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11936 foreach (Expression e in initializers) {
11937 Expression expr = e.CreateExpressionTree (ec);
11939 expr_initializers.Add (expr);
11943 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11945 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11948 protected override Expression DoResolve (ResolveContext ec)
11950 List<string> element_names = null;
11951 for (int i = 0; i < initializers.Count; ++i) {
11952 Expression initializer = initializers [i];
11953 ElementInitializer element_initializer = initializer as ElementInitializer;
11956 if (element_initializer != null) {
11957 element_names = new List<string> (initializers.Count);
11958 if (!element_initializer.IsDictionaryInitializer)
11959 element_names.Add (element_initializer.Name);
11960 } else if (initializer is CompletingExpression) {
11961 initializer.Resolve (ec);
11962 throw new InternalErrorException ("This line should never be reached");
11964 var t = ec.CurrentInitializerVariable.Type;
11965 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11966 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11967 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11968 "object initializer because type `{1}' does not implement `{2}' interface",
11969 ec.CurrentInitializerVariable.GetSignatureForError (),
11970 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11971 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11974 is_collection_initialization = true;
11977 if (is_collection_initialization != (element_initializer == null)) {
11978 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11979 is_collection_initialization ? "collection initializer" : "object initializer");
11983 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11984 if (element_names.Contains (element_initializer.Name)) {
11985 ec.Report.Error (1912, element_initializer.Location,
11986 "An object initializer includes more than one member `{0}' initialization",
11987 element_initializer.Name);
11989 element_names.Add (element_initializer.Name);
11994 Expression e = initializer.Resolve (ec);
11995 if (e == EmptyExpressionStatement.Instance)
11996 initializers.RemoveAt (i--);
11998 initializers [i] = e;
12001 type = ec.CurrentInitializerVariable.Type;
12002 if (is_collection_initialization) {
12003 if (TypeManager.HasElementType (type)) {
12004 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12005 type.GetSignatureForError ());
12009 eclass = ExprClass.Variable;
12013 public override void Emit (EmitContext ec)
12015 EmitStatement (ec);
12018 public override void EmitStatement (EmitContext ec)
12020 foreach (ExpressionStatement e in initializers) {
12021 // TODO: need location region
12022 ec.Mark (e.Location);
12023 e.EmitStatement (ec);
12027 public override void FlowAnalysis (FlowAnalysisContext fc)
12029 foreach (var initializer in initializers) {
12030 if (initializer != null)
12031 initializer.FlowAnalysis (fc);
12037 // New expression with element/object initializers
12039 public class NewInitialize : New
12042 // This class serves as a proxy for variable initializer target instances.
12043 // A real variable is assigned later when we resolve left side of an
12046 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12048 NewInitialize new_instance;
12050 public InitializerTargetExpression (NewInitialize newInstance)
12052 this.type = newInstance.type;
12053 this.loc = newInstance.loc;
12054 this.eclass = newInstance.eclass;
12055 this.new_instance = newInstance;
12058 public override bool ContainsEmitWithAwait ()
12063 public override Expression CreateExpressionTree (ResolveContext ec)
12065 // Should not be reached
12066 throw new NotSupportedException ("ET");
12069 protected override Expression DoResolve (ResolveContext ec)
12074 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12079 public override void Emit (EmitContext ec)
12081 Expression e = (Expression) new_instance.instance;
12085 public override Expression EmitToField (EmitContext ec)
12087 return (Expression) new_instance.instance;
12090 #region IMemoryLocation Members
12092 public void AddressOf (EmitContext ec, AddressOp mode)
12094 new_instance.instance.AddressOf (ec, mode);
12100 CollectionOrObjectInitializers initializers;
12101 IMemoryLocation instance;
12102 DynamicExpressionStatement dynamic;
12104 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12105 : base (requested_type, arguments, l)
12107 this.initializers = initializers;
12110 public CollectionOrObjectInitializers Initializers {
12112 return initializers;
12116 protected override void CloneTo (CloneContext clonectx, Expression t)
12118 base.CloneTo (clonectx, t);
12120 NewInitialize target = (NewInitialize) t;
12121 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12124 public override bool ContainsEmitWithAwait ()
12126 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12129 public override Expression CreateExpressionTree (ResolveContext ec)
12131 Arguments args = new Arguments (2);
12132 args.Add (new Argument (base.CreateExpressionTree (ec)));
12133 if (!initializers.IsEmpty)
12134 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12136 return CreateExpressionFactoryCall (ec,
12137 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12141 protected override Expression DoResolve (ResolveContext ec)
12143 Expression e = base.DoResolve (ec);
12147 if (type.IsDelegate) {
12148 ec.Report.Error (1958, Initializers.Location,
12149 "Object and collection initializers cannot be used to instantiate a delegate");
12152 Expression previous = ec.CurrentInitializerVariable;
12153 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12154 initializers.Resolve (ec);
12155 ec.CurrentInitializerVariable = previous;
12157 dynamic = e as DynamicExpressionStatement;
12158 if (dynamic != null)
12164 public override void Emit (EmitContext ec)
12166 if (!CanEmitOptimizedLocalTarget (ec)) {
12167 var fe = ec.GetTemporaryField (type);
12169 if (!Emit (ec, fe))
12178 public override bool Emit (EmitContext ec, IMemoryLocation target)
12181 // Expression is initialized into temporary target then moved
12182 // to real one for atomicity
12184 IMemoryLocation temp_target = target;
12186 LocalTemporary temp = null;
12187 bool by_ref = false;
12188 if (!initializers.IsEmpty) {
12189 temp_target = target as LocalTemporary;
12190 if (temp_target == null)
12191 temp_target = target as StackFieldExpr;
12193 if (temp_target == null) {
12194 var vr = target as VariableReference;
12195 if (vr != null && vr.IsRef) {
12201 if (temp_target == null)
12202 temp_target = temp = new LocalTemporary (type);
12205 bool left_on_stack;
12206 if (dynamic != null) {
12208 left_on_stack = true;
12210 left_on_stack = base.Emit (ec, temp_target);
12213 if (initializers.IsEmpty)
12214 return left_on_stack;
12216 StackFieldExpr sf = null;
12218 // Move a new instance (reference-type) to local temporary variable
12219 if (left_on_stack) {
12221 temp_target = temp = new LocalTemporary (type);
12227 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12229 throw new NotImplementedException ();
12231 sf = ec.GetTemporaryField (type);
12232 sf.EmitAssign (ec, temp, false, false);
12235 left_on_stack = false;
12239 instance = temp_target;
12241 initializers.Emit (ec);
12243 ((Expression)temp_target).Emit (ec);
12249 sf.IsAvailableForReuse = true;
12254 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12256 return !(method == null && TypeSpec.IsValueType (type) &&
12257 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12258 initializers.ContainsEmitWithAwait ());
12261 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12263 instance = base.EmitAddressOf (ec, Mode);
12265 if (!initializers.IsEmpty)
12266 initializers.Emit (ec);
12271 public override void FlowAnalysis (FlowAnalysisContext fc)
12273 base.FlowAnalysis (fc);
12274 initializers.FlowAnalysis (fc);
12277 public override object Accept (StructuralVisitor visitor)
12279 return visitor.Visit (this);
12283 public class NewAnonymousType : New
12285 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12287 List<AnonymousTypeParameter> parameters;
12288 readonly TypeContainer parent;
12289 AnonymousTypeClass anonymous_type;
12291 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12292 : base (null, null, loc)
12294 this.parameters = parameters;
12295 this.parent = parent;
12298 public List<AnonymousTypeParameter> Parameters {
12300 return this.parameters;
12304 protected override void CloneTo (CloneContext clonectx, Expression target)
12306 if (parameters == null)
12309 NewAnonymousType t = (NewAnonymousType) target;
12310 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12311 foreach (AnonymousTypeParameter atp in parameters)
12312 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12315 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12317 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12321 type = AnonymousTypeClass.Create (parent, parameters, loc);
12325 int errors = ec.Report.Errors;
12326 type.CreateContainer ();
12327 type.DefineContainer ();
12329 if ((ec.Report.Errors - errors) == 0) {
12330 parent.Module.AddAnonymousType (type);
12331 type.PrepareEmit ();
12337 public override Expression CreateExpressionTree (ResolveContext ec)
12339 if (parameters == null)
12340 return base.CreateExpressionTree (ec);
12342 var init = new ArrayInitializer (parameters.Count, loc);
12343 foreach (var m in anonymous_type.Members) {
12344 var p = m as Property;
12346 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12349 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12350 foreach (Argument a in arguments)
12351 ctor_args.Add (a.CreateExpressionTree (ec));
12353 Arguments args = new Arguments (3);
12354 args.Add (new Argument (new TypeOfMethod (method, loc)));
12355 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12356 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12358 return CreateExpressionFactoryCall (ec, "New", args);
12361 protected override Expression DoResolve (ResolveContext ec)
12363 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12364 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12368 if (parameters == null) {
12369 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12370 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12371 return base.DoResolve (ec);
12374 bool error = false;
12375 arguments = new Arguments (parameters.Count);
12376 var t_args = new TypeSpec [parameters.Count];
12377 for (int i = 0; i < parameters.Count; ++i) {
12378 Expression e = parameters [i].Resolve (ec);
12384 arguments.Add (new Argument (e));
12385 t_args [i] = e.Type;
12391 anonymous_type = CreateAnonymousType (ec, parameters);
12392 if (anonymous_type == null)
12395 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12396 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12397 eclass = ExprClass.Value;
12401 public override object Accept (StructuralVisitor visitor)
12403 return visitor.Visit (this);
12407 public class AnonymousTypeParameter : ShimExpression
12409 public readonly string Name;
12411 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12412 : base (initializer)
12418 public AnonymousTypeParameter (Parameter parameter)
12419 : base (new SimpleName (parameter.Name, parameter.Location))
12421 this.Name = parameter.Name;
12422 this.loc = parameter.Location;
12425 public override bool Equals (object o)
12427 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12428 return other != null && Name == other.Name;
12431 public override int GetHashCode ()
12433 return Name.GetHashCode ();
12436 protected override Expression DoResolve (ResolveContext ec)
12438 Expression e = expr.Resolve (ec);
12442 if (e.eclass == ExprClass.MethodGroup) {
12443 Error_InvalidInitializer (ec, e.ExprClassName);
12448 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12449 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12456 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12458 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12459 Name, initializer);
12463 public class CatchFilterExpression : BooleanExpression
12465 public CatchFilterExpression (Expression expr, Location loc)
12472 public class InterpolatedString : Expression
12474 readonly StringLiteral start, end;
12475 List<Expression> interpolations;
12476 Arguments arguments;
12478 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12480 this.start = start;
12482 this.interpolations = interpolations;
12483 loc = start.Location;
12486 protected override void CloneTo (CloneContext clonectx, Expression t)
12488 InterpolatedString target = (InterpolatedString) t;
12490 if (interpolations != null) {
12491 target.interpolations = new List<Expression> ();
12492 foreach (var interpolation in interpolations) {
12493 target.interpolations.Add (interpolation.Clone (clonectx));
12498 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12500 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12501 if (factory == null)
12504 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12505 var res = new Invocation (ma, arguments).Resolve (rc);
12506 if (res != null && res.Type != type)
12507 res = Convert.ExplicitConversion (rc, res, type, loc);
12512 public override bool ContainsEmitWithAwait ()
12514 if (interpolations == null)
12517 foreach (var expr in interpolations) {
12518 if (expr.ContainsEmitWithAwait ())
12525 public override Expression CreateExpressionTree (ResolveContext rc)
12527 var best = ResolveBestFormatOverload (rc);
12531 Expression instance = new NullLiteral (loc);
12532 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12533 return CreateExpressionFactoryCall (rc, "Call", args);
12536 protected override Expression DoResolve (ResolveContext rc)
12540 if (interpolations == null) {
12542 arguments = new Arguments (1);
12544 arguments = new Arguments (interpolations.Count);
12546 var sb = new StringBuilder (start.Value);
12547 for (int i = 0; i < interpolations.Count; ++i) {
12549 sb.Append ('{').Append (i / 2);
12550 var isi = (InterpolatedStringInsert)interpolations [i];
12551 if (isi.Alignment != null) {
12553 var value = isi.ResolveAligment (rc);
12555 sb.Append (value.Value);
12558 if (isi.Format != null) {
12560 sb.Append (isi.Format);
12564 arguments.Add (new Argument (isi.Resolve (rc)));
12566 sb.Append (((StringLiteral)interpolations [i]).Value);
12570 sb.Append (end.Value);
12571 str = sb.ToString ();
12574 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12576 eclass = ExprClass.Value;
12577 type = rc.BuiltinTypes.String;
12581 public override void Emit (EmitContext ec)
12583 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12584 if (interpolations == null) {
12585 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12586 if (str != start.Value)
12587 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12594 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12598 var ca = new CallEmitter ();
12599 ca.Emit (ec, best, arguments, loc);
12602 public override void FlowAnalysis (FlowAnalysisContext fc)
12604 if (interpolations != null) {
12605 foreach (var expr in interpolations) {
12606 expr.FlowAnalysis (fc);
12611 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12613 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12614 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12615 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12619 public class InterpolatedStringInsert : CompositeExpression
12621 public InterpolatedStringInsert (Expression expr)
12626 public Expression Alignment { get; set; }
12627 public string Format { get; set; }
12629 protected override void CloneTo (CloneContext clonectx, Expression t)
12631 var target = (InterpolatedStringInsert)t;
12632 target.expr = expr.Clone (clonectx);
12633 if (Alignment != null)
12634 target.Alignment = Alignment.Clone (clonectx);
12637 protected override Expression DoResolve (ResolveContext rc)
12639 var expr = base.DoResolve (rc);
12644 // For better error reporting, assumes the built-in implementation uses object
12647 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12650 public override void FlowAnalysis (FlowAnalysisContext fc)
12652 Child.FlowAnalysis (fc);
12655 public int? ResolveAligment (ResolveContext rc)
12657 var c = Alignment.ResolveLabelConstant (rc);
12661 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12665 var value = (int) c.GetValueAsLong ();
12666 if (value > 32767 || value < -32767) {
12667 rc.Report.Warning (8094, 1, Alignment.Location,
12668 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");