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 var await_field = EmitToFieldSource (ec);
8402 if (await_field != null)
8403 await_field.Emit (ec);
8406 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8408 if (first_emit != null) {
8409 first_emit.Emit (ec);
8410 first_emit_temp.Store (ec);
8413 StackFieldExpr await_stack_field;
8414 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8415 await_stack_field = ec.GetTemporaryField (type);
8418 await_stack_field = null;
8421 EmitExpressionsList (ec, arguments);
8423 ec.EmitArrayNew ((ArrayContainer) type);
8425 if (initializers == null)
8426 return await_stack_field;
8428 if (await_stack_field != null)
8429 await_stack_field.EmitAssignFromStack (ec);
8433 // Emit static initializer for arrays which contain more than 2 items and
8434 // the static initializer will initialize at least 25% of array values or there
8435 // is more than 10 items to be initialized
8437 // NOTE: const_initializers_count does not contain default constant values.
8439 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8440 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8441 EmitStaticInitializers (ec, await_stack_field);
8443 if (!only_constant_initializers)
8444 EmitDynamicInitializers (ec, false, await_stack_field);
8448 EmitDynamicInitializers (ec, true, await_stack_field);
8451 if (first_emit_temp != null)
8452 first_emit_temp.Release (ec);
8454 return await_stack_field;
8457 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8459 // no multi dimensional or jagged arrays
8460 if (arguments.Count != 1 || array_element_type.IsArray) {
8461 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8465 // No array covariance, except for array -> object
8466 if (type != targetType) {
8467 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8468 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8472 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8473 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8478 // Single dimensional array of 0 size
8479 if (array_data == null) {
8480 IntConstant ic = arguments[0] as IntConstant;
8481 if (ic == null || !ic.IsDefaultValue) {
8482 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8490 enc.Encode (array_data.Count);
8491 foreach (var element in array_data) {
8492 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8496 protected override void CloneTo (CloneContext clonectx, Expression t)
8498 ArrayCreation target = (ArrayCreation) t;
8500 if (requested_base_type != null)
8501 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8503 if (arguments != null){
8504 target.arguments = new List<Expression> (arguments.Count);
8505 foreach (Expression e in arguments)
8506 target.arguments.Add (e.Clone (clonectx));
8509 if (initializers != null)
8510 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8513 public override object Accept (StructuralVisitor visitor)
8515 return visitor.Visit (this);
8520 // Represents an implicitly typed array epxression
8522 class ImplicitlyTypedArrayCreation : ArrayCreation
8524 TypeInferenceContext best_type_inference;
8526 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8527 : base (null, rank, initializers, loc)
8531 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8532 : base (null, initializers, loc)
8536 protected override Expression DoResolve (ResolveContext ec)
8541 dimensions = rank.Dimension;
8543 best_type_inference = new TypeInferenceContext ();
8545 if (!ResolveInitializers (ec))
8548 best_type_inference.FixAllTypes (ec);
8549 array_element_type = best_type_inference.InferredTypeArguments[0];
8550 best_type_inference = null;
8552 if (array_element_type == null ||
8553 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8554 arguments.Count != rank.Dimension) {
8555 ec.Report.Error (826, loc,
8556 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8561 // At this point we found common base type for all initializer elements
8562 // but we have to be sure that all static initializer elements are of
8565 UnifyInitializerElement (ec);
8567 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8568 eclass = ExprClass.Value;
8573 // Converts static initializer only
8575 void UnifyInitializerElement (ResolveContext ec)
8577 for (int i = 0; i < array_data.Count; ++i) {
8578 Expression e = array_data[i];
8580 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8584 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8586 element = element.Resolve (ec);
8587 if (element != null)
8588 best_type_inference.AddCommonTypeBound (element.Type);
8594 sealed class CompilerGeneratedThis : This
8596 public CompilerGeneratedThis (TypeSpec type, Location loc)
8602 protected override Expression DoResolve (ResolveContext rc)
8604 eclass = ExprClass.Variable;
8606 var block = rc.CurrentBlock;
8607 if (block != null) {
8608 var top = block.ParametersBlock.TopBlock;
8609 if (top.ThisVariable != null)
8610 variable_info = top.ThisVariable.VariableInfo;
8617 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8619 return DoResolve (rc);
8622 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8629 /// Represents the `this' construct
8632 public class This : VariableReference
8634 sealed class ThisVariable : ILocalVariable
8636 public static readonly ILocalVariable Instance = new ThisVariable ();
8638 public void Emit (EmitContext ec)
8643 public void EmitAssign (EmitContext ec)
8645 throw new InvalidOperationException ();
8648 public void EmitAddressOf (EmitContext ec)
8654 protected VariableInfo variable_info;
8656 public This (Location loc)
8663 public override string Name {
8664 get { return "this"; }
8667 public override bool IsLockedByStatement {
8675 public override bool IsRef {
8676 get { return type.IsStruct; }
8679 public override bool IsSideEffectFree {
8685 protected override ILocalVariable Variable {
8686 get { return ThisVariable.Instance; }
8689 public override VariableInfo VariableInfo {
8690 get { return variable_info; }
8693 public override bool IsFixed {
8694 get { return false; }
8699 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8702 // It's null for all cases when we don't need to check `this'
8703 // definitive assignment
8705 if (variable_info == null)
8708 if (fc.IsDefinitelyAssigned (variable_info))
8711 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8714 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8716 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8717 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8718 } else if (ec.CurrentAnonymousMethod != null) {
8719 ec.Report.Error (1673, loc,
8720 "Anonymous methods inside structs cannot access instance members of `this'. " +
8721 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8723 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8727 public override void FlowAnalysis (FlowAnalysisContext fc)
8729 CheckStructThisDefiniteAssignment (fc);
8732 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8737 AnonymousMethodStorey storey = ae.Storey;
8738 return storey != null ? storey.HoistedThis : null;
8741 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8743 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8746 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8749 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8755 public virtual void ResolveBase (ResolveContext ec)
8757 eclass = ExprClass.Variable;
8758 type = ec.CurrentType;
8760 if (!IsThisAvailable (ec, false)) {
8761 Error_ThisNotAvailable (ec);
8765 var block = ec.CurrentBlock;
8766 if (block != null) {
8767 var top = block.ParametersBlock.TopBlock;
8768 if (top.ThisVariable != null)
8769 variable_info = top.ThisVariable.VariableInfo;
8771 AnonymousExpression am = ec.CurrentAnonymousMethod;
8772 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8774 // Hoisted this is almost like hoisted variable but not exactly. When
8775 // there is no variable hoisted we can simply emit an instance method
8776 // without lifting this into a storey. Unfotunatelly this complicates
8777 // things in other cases because we don't know where this will be hoisted
8778 // until top-level block is fully resolved
8780 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8781 am.SetHasThisAccess ();
8786 protected override Expression DoResolve (ResolveContext ec)
8792 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8794 if (eclass == ExprClass.Unresolved)
8798 if (right_side == EmptyExpression.UnaryAddress)
8799 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8800 else if (right_side == EmptyExpression.OutAccess)
8801 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8803 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8809 public override int GetHashCode()
8811 throw new NotImplementedException ();
8814 public override bool Equals (object obj)
8816 This t = obj as This;
8823 protected override void CloneTo (CloneContext clonectx, Expression t)
8828 public override void SetHasAddressTaken ()
8833 public override object Accept (StructuralVisitor visitor)
8835 return visitor.Visit (this);
8840 /// Represents the `__arglist' construct
8842 public class ArglistAccess : Expression
8844 public ArglistAccess (Location loc)
8849 protected override void CloneTo (CloneContext clonectx, Expression target)
8854 public override bool ContainsEmitWithAwait ()
8859 public override Expression CreateExpressionTree (ResolveContext ec)
8861 throw new NotSupportedException ("ET");
8864 protected override Expression DoResolve (ResolveContext ec)
8866 eclass = ExprClass.Variable;
8867 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8869 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8870 ec.Report.Error (190, loc,
8871 "The __arglist construct is valid only within a variable argument method");
8877 public override void Emit (EmitContext ec)
8879 ec.Emit (OpCodes.Arglist);
8882 public override object Accept (StructuralVisitor visitor)
8884 return visitor.Visit (this);
8889 /// Represents the `__arglist (....)' construct
8891 public class Arglist : Expression
8893 Arguments arguments;
8895 public Arglist (Location loc)
8900 public Arglist (Arguments args, Location l)
8906 public Arguments Arguments {
8912 public MetaType[] ArgumentTypes {
8914 if (arguments == null)
8915 return MetaType.EmptyTypes;
8917 var retval = new MetaType[arguments.Count];
8918 for (int i = 0; i < retval.Length; i++)
8919 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8925 public override bool ContainsEmitWithAwait ()
8927 throw new NotImplementedException ();
8930 public override Expression CreateExpressionTree (ResolveContext ec)
8932 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8936 protected override Expression DoResolve (ResolveContext ec)
8938 eclass = ExprClass.Variable;
8939 type = InternalType.Arglist;
8940 if (arguments != null) {
8941 bool dynamic; // Can be ignored as there is always only 1 overload
8942 arguments.Resolve (ec, out dynamic);
8948 public override void Emit (EmitContext ec)
8950 if (arguments != null)
8951 arguments.Emit (ec);
8954 protected override void CloneTo (CloneContext clonectx, Expression t)
8956 Arglist target = (Arglist) t;
8958 if (arguments != null)
8959 target.arguments = arguments.Clone (clonectx);
8962 public override object Accept (StructuralVisitor visitor)
8964 return visitor.Visit (this);
8968 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8970 FullNamedExpression texpr;
8972 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8979 public FullNamedExpression TypeExpression {
8985 public override bool ContainsEmitWithAwait ()
8990 public void AddressOf (EmitContext ec, AddressOp mode)
8993 ec.Emit (OpCodes.Refanyval, type);
8996 protected override Expression DoResolve (ResolveContext rc)
8998 expr = expr.Resolve (rc);
8999 type = texpr.ResolveAsType (rc);
9000 if (expr == null || type == null)
9003 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9004 eclass = ExprClass.Variable;
9008 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9010 return DoResolve (rc);
9013 public override void Emit (EmitContext ec)
9016 ec.Emit (OpCodes.Refanyval, type);
9017 ec.EmitLoadFromPtr (type);
9020 public void Emit (EmitContext ec, bool leave_copy)
9022 throw new NotImplementedException ();
9025 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9028 ec.Emit (OpCodes.Refanyval, type);
9031 LocalTemporary temporary = null;
9033 ec.Emit (OpCodes.Dup);
9034 temporary = new LocalTemporary (source.Type);
9035 temporary.Store (ec);
9038 ec.EmitStoreFromPtr (type);
9040 if (temporary != null) {
9041 temporary.Emit (ec);
9042 temporary.Release (ec);
9046 public override object Accept (StructuralVisitor visitor)
9048 return visitor.Visit (this);
9052 public class RefTypeExpr : ShimExpression
9054 public RefTypeExpr (Expression expr, Location loc)
9060 protected override Expression DoResolve (ResolveContext rc)
9062 expr = expr.Resolve (rc);
9066 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9070 type = rc.BuiltinTypes.Type;
9071 eclass = ExprClass.Value;
9075 public override void Emit (EmitContext ec)
9078 ec.Emit (OpCodes.Refanytype);
9079 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9081 ec.Emit (OpCodes.Call, m);
9084 public override object Accept (StructuralVisitor visitor)
9086 return visitor.Visit (this);
9090 public class MakeRefExpr : ShimExpression
9092 public MakeRefExpr (Expression expr, Location loc)
9098 public override bool ContainsEmitWithAwait ()
9100 throw new NotImplementedException ();
9103 protected override Expression DoResolve (ResolveContext rc)
9105 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9106 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9107 eclass = ExprClass.Value;
9111 public override void Emit (EmitContext ec)
9113 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9114 ec.Emit (OpCodes.Mkrefany, expr.Type);
9117 public override object Accept (StructuralVisitor visitor)
9119 return visitor.Visit (this);
9124 /// Implements the typeof operator
9126 public class TypeOf : Expression {
9127 FullNamedExpression QueriedType;
9130 public TypeOf (FullNamedExpression queried_type, Location l)
9132 QueriedType = queried_type;
9137 // Use this constructor for any compiler generated typeof expression
9139 public TypeOf (TypeSpec type, Location loc)
9141 this.typearg = type;
9147 public override bool IsSideEffectFree {
9153 public TypeSpec TypeArgument {
9159 public FullNamedExpression TypeExpression {
9168 protected override void CloneTo (CloneContext clonectx, Expression t)
9170 TypeOf target = (TypeOf) t;
9171 if (QueriedType != null)
9172 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9175 public override bool ContainsEmitWithAwait ()
9180 public override Expression CreateExpressionTree (ResolveContext ec)
9182 Arguments args = new Arguments (2);
9183 args.Add (new Argument (this));
9184 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9185 return CreateExpressionFactoryCall (ec, "Constant", args);
9188 protected override Expression DoResolve (ResolveContext ec)
9190 if (eclass != ExprClass.Unresolved)
9193 if (typearg == null) {
9195 // Pointer types are allowed without explicit unsafe, they are just tokens
9197 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9198 typearg = QueriedType.ResolveAsType (ec, true);
9201 if (typearg == null)
9204 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9205 ec.Report.Error (1962, QueriedType.Location,
9206 "The typeof operator cannot be used on the dynamic type");
9210 type = ec.BuiltinTypes.Type;
9212 // Even though what is returned is a type object, it's treated as a value by the compiler.
9213 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9214 eclass = ExprClass.Value;
9218 static bool ContainsDynamicType (TypeSpec type)
9220 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9223 var element_container = type as ElementTypeSpec;
9224 if (element_container != null)
9225 return ContainsDynamicType (element_container.Element);
9227 foreach (var t in type.TypeArguments) {
9228 if (ContainsDynamicType (t)) {
9236 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9238 // Target type is not System.Type therefore must be object
9239 // and we need to use different encoding sequence
9240 if (targetType != type)
9243 if (typearg is InflatedTypeSpec) {
9246 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9247 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9248 typearg.GetSignatureForError ());
9252 gt = gt.DeclaringType;
9253 } while (gt != null);
9256 if (ContainsDynamicType (typearg)) {
9257 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9261 enc.EncodeTypeName (typearg);
9264 public override void Emit (EmitContext ec)
9266 ec.Emit (OpCodes.Ldtoken, typearg);
9267 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9269 ec.Emit (OpCodes.Call, m);
9272 public override object Accept (StructuralVisitor visitor)
9274 return visitor.Visit (this);
9278 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9280 public TypeOfMethod (MethodSpec method, Location loc)
9281 : base (method, loc)
9285 protected override Expression DoResolve (ResolveContext ec)
9287 if (member.IsConstructor) {
9288 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9290 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9296 return base.DoResolve (ec);
9299 public override void Emit (EmitContext ec)
9301 ec.Emit (OpCodes.Ldtoken, member);
9304 ec.Emit (OpCodes.Castclass, type);
9307 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9309 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9312 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9314 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9318 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9320 protected readonly T member;
9322 protected TypeOfMember (T member, Location loc)
9324 this.member = member;
9328 public override bool IsSideEffectFree {
9334 public override bool ContainsEmitWithAwait ()
9339 public override Expression CreateExpressionTree (ResolveContext ec)
9341 Arguments args = new Arguments (2);
9342 args.Add (new Argument (this));
9343 args.Add (new Argument (new TypeOf (type, loc)));
9344 return CreateExpressionFactoryCall (ec, "Constant", args);
9347 protected override Expression DoResolve (ResolveContext ec)
9349 eclass = ExprClass.Value;
9353 public override void Emit (EmitContext ec)
9355 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9356 PredefinedMember<MethodSpec> p;
9358 p = GetTypeFromHandleGeneric (ec);
9359 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9361 p = GetTypeFromHandle (ec);
9364 var mi = p.Resolve (loc);
9366 ec.Emit (OpCodes.Call, mi);
9369 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9370 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9373 sealed class TypeOfField : TypeOfMember<FieldSpec>
9375 public TypeOfField (FieldSpec field, Location loc)
9380 protected override Expression DoResolve (ResolveContext ec)
9382 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9386 return base.DoResolve (ec);
9389 public override void Emit (EmitContext ec)
9391 ec.Emit (OpCodes.Ldtoken, member);
9395 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9397 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9400 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9402 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9407 /// Implements the sizeof expression
9409 public class SizeOf : Expression {
9410 readonly Expression texpr;
9411 TypeSpec type_queried;
9413 public SizeOf (Expression queried_type, Location l)
9415 this.texpr = queried_type;
9419 public override bool IsSideEffectFree {
9425 public Expression TypeExpression {
9431 public override bool ContainsEmitWithAwait ()
9436 public override Expression CreateExpressionTree (ResolveContext ec)
9438 Error_PointerInsideExpressionTree (ec);
9442 protected override Expression DoResolve (ResolveContext ec)
9444 type_queried = texpr.ResolveAsType (ec);
9445 if (type_queried == null)
9448 if (type_queried.IsEnum)
9449 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9451 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9453 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9456 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9461 ec.Report.Error (233, loc,
9462 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9463 type_queried.GetSignatureForError ());
9466 type = ec.BuiltinTypes.Int;
9467 eclass = ExprClass.Value;
9471 public override void Emit (EmitContext ec)
9473 ec.Emit (OpCodes.Sizeof, type_queried);
9476 protected override void CloneTo (CloneContext clonectx, Expression t)
9480 public override object Accept (StructuralVisitor visitor)
9482 return visitor.Visit (this);
9487 /// Implements the qualified-alias-member (::) expression.
9489 public class QualifiedAliasMember : MemberAccess
9491 readonly string alias;
9492 public static readonly string GlobalAlias = "global";
9494 public QualifiedAliasMember (string alias, string identifier, Location l)
9495 : base (null, identifier, l)
9500 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9501 : base (null, identifier, targs, l)
9506 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9507 : base (null, identifier, arity, l)
9512 public string Alias {
9518 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9520 if (alias == GlobalAlias)
9521 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9523 int errors = mc.Module.Compiler.Report.Errors;
9524 var expr = mc.LookupNamespaceAlias (alias);
9526 if (errors == mc.Module.Compiler.Report.Errors)
9527 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9535 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9537 expr = CreateExpressionFromAlias (mc);
9541 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9544 protected override Expression DoResolve (ResolveContext rc)
9546 return ResolveAsTypeOrNamespace (rc, false);
9549 public override string GetSignatureForError ()
9552 if (targs != null) {
9553 name = Name + "<" + targs.GetSignatureForError () + ">";
9556 return alias + "::" + name;
9559 public override bool HasConditionalAccess ()
9564 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9566 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9567 rc.Module.Compiler.Report.Error (687, loc,
9568 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9569 GetSignatureForError ());
9574 return DoResolve (rc);
9577 protected override void CloneTo (CloneContext clonectx, Expression t)
9582 public override object Accept (StructuralVisitor visitor)
9584 return visitor.Visit (this);
9589 /// Implements the member access expression
9591 public class MemberAccess : ATypeNameExpression
9593 protected Expression expr;
9595 public MemberAccess (Expression expr, string id)
9596 : base (id, expr.Location)
9601 public MemberAccess (Expression expr, string identifier, Location loc)
9602 : base (identifier, loc)
9607 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9608 : base (identifier, args, loc)
9613 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9614 : base (identifier, arity, loc)
9619 public Expression LeftExpression {
9625 public override Location StartLocation {
9627 return expr == null ? loc : expr.StartLocation;
9631 protected override Expression DoResolve (ResolveContext rc)
9633 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9635 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9640 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9642 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9644 if (e is TypeExpr) {
9645 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9650 e = e.ResolveLValue (rc, rhs);
9655 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9657 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9658 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9660 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9663 public override bool HasConditionalAccess ()
9665 return LeftExpression.HasConditionalAccess ();
9668 public static bool IsValidDotExpression (TypeSpec type)
9670 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9671 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9673 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9676 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9678 var sn = expr as SimpleName;
9679 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9682 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9685 // Resolve expression which does have type set as we need expression type
9686 // with disable flow analysis as we don't know whether left side expression
9687 // is used as variable or type
9689 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9690 expr = expr.Resolve (rc);
9691 } else if (expr is TypeParameterExpr) {
9692 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9696 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9697 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9698 expr = expr.Resolve (rc, flags);
9701 expr = expr.Resolve (rc, flags);
9708 var ns = expr as NamespaceExpression;
9710 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9712 if (retval == null) {
9713 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9718 if (HasTypeArguments)
9719 return new GenericTypeExpr (retval.Type, targs, loc);
9721 targs.Resolve (rc, false);
9727 var cma = this as ConditionalMemberAccess;
9730 TypeSpec expr_type = expr.Type;
9731 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9732 me = expr as MemberExpr;
9734 me.ResolveInstanceExpression (rc, null);
9736 Arguments args = new Arguments (1);
9737 args.Add (new Argument (expr));
9740 return new DynamicConditionalMemberBinder (Name, args, loc);
9742 return new DynamicMemberBinder (Name, args, loc);
9746 if (!IsNullPropagatingValid (expr.Type)) {
9747 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9751 if (expr_type.IsNullableType) {
9752 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9753 expr_type = expr.Type;
9757 if (!IsValidDotExpression (expr_type)) {
9758 Error_OperatorCannotBeApplied (rc, expr_type);
9762 var lookup_arity = Arity;
9763 bool errorMode = false;
9764 Expression member_lookup;
9766 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9767 if (member_lookup == null) {
9769 // Try to look for extension method when member lookup failed
9771 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9772 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9773 if (methods != null) {
9774 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9775 if (HasTypeArguments) {
9776 if (!targs.Resolve (rc, false))
9779 emg.SetTypeArguments (rc, targs);
9783 emg.ConditionalAccess = true;
9785 // TODO: it should really skip the checks bellow
9786 return emg.Resolve (rc);
9792 if (member_lookup == null) {
9793 var dep = expr_type.GetMissingDependencies ();
9795 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9796 } else if (expr is TypeExpr) {
9797 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9799 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9805 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9806 // Leave it to overload resolution to report correct error
9807 } else if (!(member_lookup is TypeExpr)) {
9808 // TODO: rc.SymbolRelatedToPreviousError
9809 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9814 if (member_lookup != null)
9818 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9822 TypeExpr texpr = member_lookup as TypeExpr;
9823 if (texpr != null) {
9824 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9825 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9826 Name, texpr.GetSignatureForError ());
9829 if (!texpr.Type.IsAccessible (rc)) {
9830 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9831 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9835 if (HasTypeArguments) {
9836 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9839 return member_lookup;
9842 me = member_lookup as MemberExpr;
9844 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9849 me.ConditionalAccess = true;
9852 me = me.ResolveMemberAccess (rc, expr, sn);
9855 if (!targs.Resolve (rc, false))
9858 me.SetTypeArguments (rc, targs);
9864 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9866 FullNamedExpression fexpr = expr as FullNamedExpression;
9867 if (fexpr == null) {
9868 expr.ResolveAsType (rc);
9872 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9874 if (expr_resolved == null)
9877 var ns = expr_resolved as NamespaceExpression;
9879 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9881 if (retval == null) {
9882 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9883 } else if (Arity > 0) {
9884 if (HasTypeArguments) {
9885 retval = new GenericTypeExpr (retval.Type, targs, loc);
9886 if (retval.ResolveAsType (rc) == null)
9889 targs.Resolve (rc, allowUnboundTypeArguments);
9891 retval = new GenericOpenTypeExpr (retval.Type, loc);
9898 var tnew_expr = expr_resolved.ResolveAsType (rc);
9899 if (tnew_expr == null)
9902 TypeSpec expr_type = tnew_expr;
9903 if (TypeManager.IsGenericParameter (expr_type)) {
9904 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9905 tnew_expr.GetSignatureForError ());
9909 var qam = this as QualifiedAliasMember;
9911 rc.Module.Compiler.Report.Error (431, loc,
9912 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9917 TypeSpec nested = null;
9918 while (expr_type != null) {
9919 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9920 if (nested == null) {
9921 if (expr_type == tnew_expr) {
9922 Error_IdentifierNotFound (rc, expr_type);
9926 expr_type = tnew_expr;
9927 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9928 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9932 if (nested.IsAccessible (rc))
9936 // Keep looking after inaccessible candidate but only if
9937 // we are not in same context as the definition itself
9939 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9942 expr_type = expr_type.BaseType;
9947 if (HasTypeArguments) {
9948 texpr = new GenericTypeExpr (nested, targs, loc);
9950 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9952 texpr = new GenericOpenTypeExpr (nested, loc);
9954 } else if (expr_resolved is GenericOpenTypeExpr) {
9955 texpr = new GenericOpenTypeExpr (nested, loc);
9957 texpr = new TypeExpression (nested, loc);
9960 if (texpr.ResolveAsType (rc) == null)
9966 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9968 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9970 if (nested != null) {
9971 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9975 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9976 if (any_other_member != null) {
9977 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9981 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9982 Name, expr_type.GetSignatureForError ());
9985 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9987 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9990 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9992 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9993 ec.Report.SymbolRelatedToPreviousError (type);
9995 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9997 // a using directive or an assembly reference
9999 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10001 missing = "an assembly reference";
10004 ec.Report.Error (1061, loc,
10005 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10006 type.GetSignatureForError (), name, missing);
10010 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10013 public override string GetSignatureForError ()
10015 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10018 protected override void CloneTo (CloneContext clonectx, Expression t)
10020 MemberAccess target = (MemberAccess) t;
10022 target.expr = expr.Clone (clonectx);
10025 public override object Accept (StructuralVisitor visitor)
10027 return visitor.Visit (this);
10031 public class ConditionalMemberAccess : MemberAccess
10033 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10034 : base (expr, identifier, args, loc)
10038 public override bool HasConditionalAccess ()
10045 /// Implements checked expressions
10047 public class CheckedExpr : Expression {
10049 public Expression Expr;
10051 public CheckedExpr (Expression e, Location l)
10057 public override bool ContainsEmitWithAwait ()
10059 return Expr.ContainsEmitWithAwait ();
10062 public override Expression CreateExpressionTree (ResolveContext ec)
10064 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10065 return Expr.CreateExpressionTree (ec);
10068 protected override Expression DoResolve (ResolveContext ec)
10070 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10071 Expr = Expr.Resolve (ec);
10076 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10079 eclass = Expr.eclass;
10084 public override void Emit (EmitContext ec)
10086 using (ec.With (EmitContext.Options.CheckedScope, true))
10090 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10092 using (ec.With (EmitContext.Options.CheckedScope, true))
10093 Expr.EmitBranchable (ec, target, on_true);
10096 public override void FlowAnalysis (FlowAnalysisContext fc)
10098 Expr.FlowAnalysis (fc);
10101 public override SLE.Expression MakeExpression (BuilderContext ctx)
10103 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10104 return Expr.MakeExpression (ctx);
10108 protected override void CloneTo (CloneContext clonectx, Expression t)
10110 CheckedExpr target = (CheckedExpr) t;
10112 target.Expr = Expr.Clone (clonectx);
10115 public override object Accept (StructuralVisitor visitor)
10117 return visitor.Visit (this);
10122 /// Implements the unchecked expression
10124 public class UnCheckedExpr : Expression {
10126 public Expression Expr;
10128 public UnCheckedExpr (Expression e, Location l)
10134 public override bool ContainsEmitWithAwait ()
10136 return Expr.ContainsEmitWithAwait ();
10139 public override Expression CreateExpressionTree (ResolveContext ec)
10141 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10142 return Expr.CreateExpressionTree (ec);
10145 protected override Expression DoResolve (ResolveContext ec)
10147 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10148 Expr = Expr.Resolve (ec);
10153 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10156 eclass = Expr.eclass;
10161 public override void Emit (EmitContext ec)
10163 using (ec.With (EmitContext.Options.CheckedScope, false))
10167 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10169 using (ec.With (EmitContext.Options.CheckedScope, false))
10170 Expr.EmitBranchable (ec, target, on_true);
10173 public override void FlowAnalysis (FlowAnalysisContext fc)
10175 Expr.FlowAnalysis (fc);
10178 protected override void CloneTo (CloneContext clonectx, Expression t)
10180 UnCheckedExpr target = (UnCheckedExpr) t;
10182 target.Expr = Expr.Clone (clonectx);
10185 public override object Accept (StructuralVisitor visitor)
10187 return visitor.Visit (this);
10192 /// An Element Access expression.
10194 /// During semantic analysis these are transformed into
10195 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10197 public class ElementAccess : Expression
10199 public Arguments Arguments;
10200 public Expression Expr;
10201 bool conditional_access_receiver;
10203 public ElementAccess (Expression e, Arguments args, Location loc)
10207 this.Arguments = args;
10210 public bool ConditionalAccess { get; set; }
10212 public override Location StartLocation {
10214 return Expr.StartLocation;
10218 public override bool ContainsEmitWithAwait ()
10220 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10224 // We perform some simple tests, and then to "split" the emit and store
10225 // code we create an instance of a different class, and return that.
10227 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10229 if (conditionalAccessReceiver)
10230 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10232 Expr = Expr.Resolve (ec);
10234 if (conditionalAccessReceiver)
10235 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10242 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10243 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10247 if (type.IsArray) {
10248 var aa = new ArrayAccess (this, loc) {
10249 ConditionalAccess = ConditionalAccess,
10252 if (conditionalAccessReceiver)
10253 aa.SetConditionalAccessReceiver ();
10258 if (type.IsPointer)
10259 return Expr.MakePointerAccess (ec, type, Arguments);
10261 FieldExpr fe = Expr as FieldExpr;
10263 var ff = fe.Spec as FixedFieldSpec;
10265 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10269 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10270 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10271 var indexer = new IndexerExpr (indexers, type, this) {
10272 ConditionalAccess = ConditionalAccess
10275 if (conditionalAccessReceiver)
10276 indexer.SetConditionalAccessReceiver ();
10281 Error_CannotApplyIndexing (ec, type, loc);
10286 public override Expression CreateExpressionTree (ResolveContext ec)
10288 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10289 Expr.CreateExpressionTree (ec));
10291 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10294 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10296 if (type != InternalType.ErrorType) {
10297 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10298 type.GetSignatureForError ());
10302 public override bool HasConditionalAccess ()
10304 return ConditionalAccess || Expr.HasConditionalAccess ();
10307 void ResolveConditionalAccessReceiver (ResolveContext rc)
10309 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10310 conditional_access_receiver = true;
10314 protected override Expression DoResolve (ResolveContext rc)
10316 ResolveConditionalAccessReceiver (rc);
10318 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10322 return expr.Resolve (rc);
10325 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10327 var res = CreateAccessExpression (ec, false);
10331 return res.ResolveLValue (ec, rhs);
10334 public override void Emit (EmitContext ec)
10336 throw new Exception ("Should never be reached");
10339 public override void FlowAnalysis (FlowAnalysisContext fc)
10341 Expr.FlowAnalysis (fc);
10343 Arguments.FlowAnalysis (fc);
10346 public override string GetSignatureForError ()
10348 return Expr.GetSignatureForError ();
10351 protected override void CloneTo (CloneContext clonectx, Expression t)
10353 ElementAccess target = (ElementAccess) t;
10355 target.Expr = Expr.Clone (clonectx);
10356 if (Arguments != null)
10357 target.Arguments = Arguments.Clone (clonectx);
10360 public override object Accept (StructuralVisitor visitor)
10362 return visitor.Visit (this);
10367 /// Implements array access
10369 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10371 // Points to our "data" repository
10375 LocalTemporary temp;
10377 bool? has_await_args;
10378 bool conditional_access_receiver;
10380 public ArrayAccess (ElementAccess ea_data, Location l)
10386 public bool ConditionalAccess { get; set; }
10388 public void AddressOf (EmitContext ec, AddressOp mode)
10390 var ac = (ArrayContainer) ea.Expr.Type;
10392 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10393 LoadInstanceAndArguments (ec, false, true);
10396 LoadInstanceAndArguments (ec, false, false);
10398 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10399 ec.Emit (OpCodes.Readonly);
10401 ec.EmitArrayAddress (ac);
10404 public override Expression CreateExpressionTree (ResolveContext ec)
10406 if (ConditionalAccess)
10407 Error_NullShortCircuitInsideExpressionTree (ec);
10409 return ea.CreateExpressionTree (ec);
10412 public override bool ContainsEmitWithAwait ()
10414 return ea.ContainsEmitWithAwait ();
10417 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10419 if (HasConditionalAccess ())
10420 Error_NullPropagatingLValue (ec);
10422 return DoResolve (ec);
10425 protected override Expression DoResolve (ResolveContext ec)
10427 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10429 ea.Arguments.Resolve (ec, out dynamic);
10431 var ac = ea.Expr.Type as ArrayContainer;
10432 int rank = ea.Arguments.Count;
10433 if (ac.Rank != rank) {
10434 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10435 rank.ToString (), ac.Rank.ToString ());
10440 if (type.IsPointer && !ec.IsUnsafe) {
10441 UnsafeError (ec, ea.Location);
10444 if (conditional_access_receiver)
10445 type = LiftMemberType (ec, type);
10447 foreach (Argument a in ea.Arguments) {
10448 var na = a as NamedArgument;
10450 ElementAccess.Error_NamedArgument (na, ec.Report);
10452 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10455 eclass = ExprClass.Variable;
10460 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10462 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10465 public override void FlowAnalysis (FlowAnalysisContext fc)
10467 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10469 ea.FlowAnalysis (fc);
10471 if (conditional_access_receiver)
10472 fc.DefiniteAssignment = da;
10475 public override bool HasConditionalAccess ()
10477 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10481 // Load the array arguments into the stack.
10483 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10485 if (prepareAwait) {
10486 ea.Expr = ea.Expr.EmitToField (ec);
10488 var ie = new InstanceEmitter (ea.Expr, false);
10489 ie.Emit (ec, ConditionalAccess);
10491 if (duplicateArguments) {
10492 ec.Emit (OpCodes.Dup);
10494 var copy = new LocalTemporary (ea.Expr.Type);
10500 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10501 if (dup_args != null)
10502 ea.Arguments = dup_args;
10505 public void Emit (EmitContext ec, bool leave_copy)
10508 ec.EmitLoadFromPtr (type);
10510 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10511 LoadInstanceAndArguments (ec, false, true);
10514 if (conditional_access_receiver)
10515 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10517 var ac = (ArrayContainer) ea.Expr.Type;
10518 LoadInstanceAndArguments (ec, false, false);
10519 ec.EmitArrayLoad (ac);
10521 if (conditional_access_receiver)
10522 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10526 ec.Emit (OpCodes.Dup);
10527 temp = new LocalTemporary (this.type);
10532 public override void Emit (EmitContext ec)
10537 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10539 var ac = (ArrayContainer) ea.Expr.Type;
10540 TypeSpec t = source.Type;
10542 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10545 // When we are dealing with a struct, get the address of it to avoid value copy
10546 // Same cannot be done for reference type because array covariance and the
10547 // check in ldelema requires to specify the type of array element stored at the index
10549 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10550 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10552 if (has_await_args.Value) {
10553 if (source.ContainsEmitWithAwait ()) {
10554 source = source.EmitToField (ec);
10555 isCompound = false;
10559 LoadInstanceAndArguments (ec, isCompound, false);
10564 ec.EmitArrayAddress (ac);
10567 ec.Emit (OpCodes.Dup);
10571 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10573 if (has_await_args.Value) {
10574 if (source.ContainsEmitWithAwait ())
10575 source = source.EmitToField (ec);
10577 LoadInstanceAndArguments (ec, false, false);
10584 var lt = ea.Expr as LocalTemporary;
10590 ec.Emit (OpCodes.Dup);
10591 temp = new LocalTemporary (this.type);
10596 ec.EmitStoreFromPtr (t);
10598 ec.EmitArrayStore (ac);
10601 if (temp != null) {
10607 public override Expression EmitToField (EmitContext ec)
10610 // Have to be specialized for arrays to get access to
10611 // underlying element. Instead of another result copy we
10612 // need direct access to element
10616 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10618 ea.Expr = ea.Expr.EmitToField (ec);
10619 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10623 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10625 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10628 public override SLE.Expression MakeExpression (BuilderContext ctx)
10630 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10633 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10635 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10636 return Arguments.MakeExpression (ea.Arguments, ctx);
10640 public void SetConditionalAccessReceiver ()
10642 conditional_access_receiver = true;
10647 // Indexer access expression
10649 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10651 IList<MemberSpec> indexers;
10652 Arguments arguments;
10653 TypeSpec queried_type;
10655 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10656 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10660 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10663 this.indexers = indexers;
10664 this.queried_type = queriedType;
10665 this.InstanceExpression = instance;
10666 this.arguments = args;
10671 protected override Arguments Arguments {
10680 protected override TypeSpec DeclaringType {
10682 return best_candidate.DeclaringType;
10686 public override bool IsInstance {
10692 public override bool IsStatic {
10698 public override string KindName {
10699 get { return "indexer"; }
10702 public override string Name {
10710 public override bool ContainsEmitWithAwait ()
10712 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10715 public override Expression CreateExpressionTree (ResolveContext ec)
10717 if (ConditionalAccess) {
10718 Error_NullShortCircuitInsideExpressionTree (ec);
10721 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10722 InstanceExpression.CreateExpressionTree (ec),
10723 new TypeOfMethod (Getter, loc));
10725 return CreateExpressionFactoryCall (ec, "Call", args);
10728 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10730 LocalTemporary await_source_arg = null;
10733 emitting_compound_assignment = true;
10734 if (source is DynamicExpressionStatement) {
10739 emitting_compound_assignment = false;
10741 if (has_await_arguments) {
10742 await_source_arg = new LocalTemporary (Type);
10743 await_source_arg.Store (ec);
10745 arguments.Add (new Argument (await_source_arg));
10748 temp = await_source_arg;
10751 has_await_arguments = false;
10756 ec.Emit (OpCodes.Dup);
10757 temp = new LocalTemporary (Type);
10763 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10764 source = source.EmitToField (ec);
10766 temp = new LocalTemporary (Type);
10773 arguments.Add (new Argument (source));
10776 var call = new CallEmitter ();
10777 call.InstanceExpression = InstanceExpression;
10778 if (arguments == null)
10779 call.InstanceExpressionOnStack = true;
10781 call.Emit (ec, Setter, arguments, loc);
10783 if (temp != null) {
10786 } else if (leave_copy) {
10790 if (await_source_arg != null) {
10791 await_source_arg.Release (ec);
10795 public override void FlowAnalysis (FlowAnalysisContext fc)
10797 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10799 base.FlowAnalysis (fc);
10800 arguments.FlowAnalysis (fc);
10802 if (conditional_access_receiver)
10803 fc.DefiniteAssignment = da;
10806 public override string GetSignatureForError ()
10808 return best_candidate.GetSignatureForError ();
10811 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10814 throw new NotSupportedException ();
10816 var value = new[] { source.MakeExpression (ctx) };
10817 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10818 return SLE.Expression.Block (
10819 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10824 public override SLE.Expression MakeExpression (BuilderContext ctx)
10827 return base.MakeExpression (ctx);
10829 var args = Arguments.MakeExpression (arguments, ctx);
10830 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10834 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10836 if (best_candidate != null)
10839 eclass = ExprClass.IndexerAccess;
10842 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10843 arguments.Resolve (rc, out dynamic);
10846 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10849 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10850 res.BaseMembersProvider = this;
10851 res.InstanceQualifier = this;
10853 // TODO: Do I need 2 argument sets?
10854 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10855 if (best_candidate != null)
10856 type = res.BestCandidateReturnType;
10857 else if (!res.BestCandidateIsDynamic)
10862 // It has dynamic arguments
10865 Arguments args = new Arguments (arguments.Count + 1);
10867 rc.Report.Error (1972, loc,
10868 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10870 args.Add (new Argument (InstanceExpression));
10872 args.AddRange (arguments);
10874 best_candidate = null;
10875 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10879 // Try to avoid resolving left expression again
10881 if (right_side != null)
10882 ResolveInstanceExpression (rc, right_side);
10887 protected override void CloneTo (CloneContext clonectx, Expression t)
10889 IndexerExpr target = (IndexerExpr) t;
10891 if (arguments != null)
10892 target.arguments = arguments.Clone (clonectx);
10895 public void SetConditionalAccessReceiver ()
10897 conditional_access_receiver = true;
10900 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10902 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10905 #region IBaseMembersProvider Members
10907 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10909 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10912 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10914 if (queried_type == member.DeclaringType)
10917 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10918 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10921 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10930 // A base access expression
10932 public class BaseThis : This
10934 public BaseThis (Location loc)
10939 public BaseThis (TypeSpec type, Location loc)
10943 eclass = ExprClass.Variable;
10948 public override string Name {
10956 public override Expression CreateExpressionTree (ResolveContext ec)
10958 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10959 return base.CreateExpressionTree (ec);
10962 public override void Emit (EmitContext ec)
10966 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10967 var context_type = ec.CurrentType;
10968 ec.Emit (OpCodes.Ldobj, context_type);
10969 ec.Emit (OpCodes.Box, context_type);
10973 protected override void Error_ThisNotAvailable (ResolveContext ec)
10976 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10978 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10982 public override void ResolveBase (ResolveContext ec)
10984 base.ResolveBase (ec);
10985 type = ec.CurrentType.BaseType;
10988 public override object Accept (StructuralVisitor visitor)
10990 return visitor.Visit (this);
10995 /// This class exists solely to pass the Type around and to be a dummy
10996 /// that can be passed to the conversion functions (this is used by
10997 /// foreach implementation to typecast the object return value from
10998 /// get_Current into the proper type. All code has been generated and
10999 /// we only care about the side effect conversions to be performed
11001 /// This is also now used as a placeholder where a no-action expression
11002 /// is needed (the `New' class).
11004 public class EmptyExpression : Expression
11006 sealed class OutAccessExpression : EmptyExpression
11008 public OutAccessExpression (TypeSpec t)
11013 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11015 rc.Report.Error (206, right_side.Location,
11016 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11022 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11023 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11024 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11025 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11026 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11027 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11028 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11029 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11031 public EmptyExpression (TypeSpec t)
11034 eclass = ExprClass.Value;
11035 loc = Location.Null;
11038 protected override void CloneTo (CloneContext clonectx, Expression target)
11042 public override bool ContainsEmitWithAwait ()
11047 public override Expression CreateExpressionTree (ResolveContext ec)
11049 throw new NotSupportedException ("ET");
11052 protected override Expression DoResolve (ResolveContext ec)
11057 public override void Emit (EmitContext ec)
11059 // nothing, as we only exist to not do anything.
11062 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11066 public override void EmitSideEffect (EmitContext ec)
11070 public override object Accept (StructuralVisitor visitor)
11072 return visitor.Visit (this);
11076 sealed class EmptyAwaitExpression : EmptyExpression
11078 public EmptyAwaitExpression (TypeSpec type)
11083 public override bool ContainsEmitWithAwait ()
11090 // Empty statement expression
11092 public sealed class EmptyExpressionStatement : ExpressionStatement
11094 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11096 private EmptyExpressionStatement ()
11098 loc = Location.Null;
11101 public override bool ContainsEmitWithAwait ()
11106 public override Expression CreateExpressionTree (ResolveContext ec)
11111 public override void EmitStatement (EmitContext ec)
11116 protected override Expression DoResolve (ResolveContext ec)
11118 eclass = ExprClass.Value;
11119 type = ec.BuiltinTypes.Object;
11123 public override void Emit (EmitContext ec)
11128 public override object Accept (StructuralVisitor visitor)
11130 return visitor.Visit (this);
11134 public class ErrorExpression : EmptyExpression
11136 public static readonly ErrorExpression Instance = new ErrorExpression ();
11138 private ErrorExpression ()
11139 : base (InternalType.ErrorType)
11143 public override Expression CreateExpressionTree (ResolveContext ec)
11148 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11153 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11157 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11161 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11165 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11169 public override object Accept (StructuralVisitor visitor)
11171 return visitor.Visit (this);
11175 public class UserCast : Expression {
11179 public UserCast (MethodSpec method, Expression source, Location l)
11181 if (source == null)
11182 throw new ArgumentNullException ("source");
11184 this.method = method;
11185 this.source = source;
11186 type = method.ReturnType;
11190 public Expression Source {
11199 public override bool ContainsEmitWithAwait ()
11201 return source.ContainsEmitWithAwait ();
11204 public override Expression CreateExpressionTree (ResolveContext ec)
11206 Arguments args = new Arguments (3);
11207 args.Add (new Argument (source.CreateExpressionTree (ec)));
11208 args.Add (new Argument (new TypeOf (type, loc)));
11209 args.Add (new Argument (new TypeOfMethod (method, loc)));
11210 return CreateExpressionFactoryCall (ec, "Convert", args);
11213 protected override Expression DoResolve (ResolveContext ec)
11215 method.CheckObsoleteness (ec, source.Location);
11217 eclass = ExprClass.Value;
11221 public override void Emit (EmitContext ec)
11224 ec.MarkCallEntry (loc);
11225 ec.Emit (OpCodes.Call, method);
11228 public override void FlowAnalysis (FlowAnalysisContext fc)
11230 source.FlowAnalysis (fc);
11233 public override string GetSignatureForError ()
11235 return TypeManager.CSharpSignature (method);
11238 public override SLE.Expression MakeExpression (BuilderContext ctx)
11241 return base.MakeExpression (ctx);
11243 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11249 // Holds additional type specifiers like ?, *, []
11251 public class ComposedTypeSpecifier
11253 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11255 public readonly int Dimension;
11256 public readonly Location Location;
11258 public ComposedTypeSpecifier (int specifier, Location loc)
11260 this.Dimension = specifier;
11261 this.Location = loc;
11265 public bool IsNullable {
11267 return Dimension == -1;
11271 public bool IsPointer {
11273 return Dimension == -2;
11277 public ComposedTypeSpecifier Next { get; set; }
11281 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11283 return new ComposedTypeSpecifier (dimension, loc);
11286 public static ComposedTypeSpecifier CreateNullable (Location loc)
11288 return new ComposedTypeSpecifier (-1, loc);
11291 public static ComposedTypeSpecifier CreatePointer (Location loc)
11293 return new ComposedTypeSpecifier (-2, loc);
11296 public string GetSignatureForError ()
11301 ArrayContainer.GetPostfixSignature (Dimension);
11303 return Next != null ? s + Next.GetSignatureForError () : s;
11308 // This class is used to "construct" the type during a typecast
11309 // operation. Since the Type.GetType class in .NET can parse
11310 // the type specification, we just use this to construct the type
11311 // one bit at a time.
11313 public class ComposedCast : TypeExpr {
11314 FullNamedExpression left;
11315 ComposedTypeSpecifier spec;
11317 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11320 throw new ArgumentNullException ("spec");
11324 this.loc = left.Location;
11327 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11329 type = left.ResolveAsType (ec);
11333 eclass = ExprClass.Type;
11335 var single_spec = spec;
11337 if (single_spec.IsNullable) {
11338 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11342 single_spec = single_spec.Next;
11343 } else if (single_spec.IsPointer) {
11345 // Declared fields cannot have unmanaged check done before all types are defined
11347 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11350 if (!ec.IsUnsafe) {
11351 UnsafeError (ec.Module.Compiler.Report, loc);
11355 type = PointerContainer.MakeType (ec.Module, type);
11356 single_spec = single_spec.Next;
11357 } while (single_spec != null && single_spec.IsPointer);
11360 if (single_spec != null && single_spec.Dimension > 0) {
11361 if (type.IsSpecialRuntimeType) {
11362 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11363 } else if (type.IsStatic) {
11364 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11365 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11366 type.GetSignatureForError ());
11368 MakeArray (ec.Module, single_spec);
11375 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11377 if (spec.Next != null)
11378 MakeArray (module, spec.Next);
11380 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11383 public override string GetSignatureForError ()
11385 return left.GetSignatureForError () + spec.GetSignatureForError ();
11388 public override object Accept (StructuralVisitor visitor)
11390 return visitor.Visit (this);
11394 class FixedBufferPtr : Expression
11396 readonly Expression array;
11398 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11400 this.type = array_type;
11401 this.array = array;
11405 public override bool ContainsEmitWithAwait ()
11407 throw new NotImplementedException ();
11410 public override Expression CreateExpressionTree (ResolveContext ec)
11412 Error_PointerInsideExpressionTree (ec);
11416 public override void Emit(EmitContext ec)
11421 protected override Expression DoResolve (ResolveContext ec)
11423 type = PointerContainer.MakeType (ec.Module, type);
11424 eclass = ExprClass.Value;
11431 // This class is used to represent the address of an array, used
11432 // only by the Fixed statement, this generates "&a [0]" construct
11433 // for fixed (char *pa = a)
11435 class ArrayPtr : FixedBufferPtr
11437 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11438 base (array, array_type, l)
11442 public override void Emit (EmitContext ec)
11447 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11452 // Encapsulates a conversion rules required for array indexes
11454 public class ArrayIndexCast : TypeCast
11456 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11457 : base (expr, returnType)
11459 if (expr.Type == returnType) // int -> int
11460 throw new ArgumentException ("unnecessary array index conversion");
11463 public override Expression CreateExpressionTree (ResolveContext ec)
11465 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11466 return base.CreateExpressionTree (ec);
11470 public override void Emit (EmitContext ec)
11474 switch (child.Type.BuiltinType) {
11475 case BuiltinTypeSpec.Type.UInt:
11476 ec.Emit (OpCodes.Conv_U);
11478 case BuiltinTypeSpec.Type.Long:
11479 ec.Emit (OpCodes.Conv_Ovf_I);
11481 case BuiltinTypeSpec.Type.ULong:
11482 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11485 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11491 // Implements the `stackalloc' keyword
11493 public class StackAlloc : Expression {
11498 public StackAlloc (Expression type, Expression count, Location l)
11501 this.count = count;
11505 public Expression TypeExpression {
11511 public Expression CountExpression {
11517 public override bool ContainsEmitWithAwait ()
11522 public override Expression CreateExpressionTree (ResolveContext ec)
11524 throw new NotSupportedException ("ET");
11527 protected override Expression DoResolve (ResolveContext ec)
11529 count = count.Resolve (ec);
11533 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11534 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11539 Constant c = count as Constant;
11540 if (c != null && c.IsNegative) {
11541 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11544 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11545 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11548 otype = texpr.ResolveAsType (ec);
11552 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11555 type = PointerContainer.MakeType (ec.Module, otype);
11556 eclass = ExprClass.Value;
11561 public override void Emit (EmitContext ec)
11563 int size = BuiltinTypeSpec.GetSize (otype);
11568 ec.Emit (OpCodes.Sizeof, otype);
11572 ec.Emit (OpCodes.Mul_Ovf_Un);
11573 ec.Emit (OpCodes.Localloc);
11576 protected override void CloneTo (CloneContext clonectx, Expression t)
11578 StackAlloc target = (StackAlloc) t;
11579 target.count = count.Clone (clonectx);
11580 target.texpr = texpr.Clone (clonectx);
11583 public override object Accept (StructuralVisitor visitor)
11585 return visitor.Visit (this);
11590 // An object initializer expression
11592 public class ElementInitializer : Assign
11594 public readonly string Name;
11596 public ElementInitializer (string name, Expression initializer, Location loc)
11597 : base (null, initializer, loc)
11602 public bool IsDictionaryInitializer {
11604 return Name == null;
11608 protected override void CloneTo (CloneContext clonectx, Expression t)
11610 ElementInitializer target = (ElementInitializer) t;
11611 target.source = source.Clone (clonectx);
11614 public override Expression CreateExpressionTree (ResolveContext ec)
11616 Arguments args = new Arguments (2);
11617 FieldExpr fe = target as FieldExpr;
11619 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11621 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11624 Expression arg_expr;
11625 var cinit = source as CollectionOrObjectInitializers;
11626 if (cinit == null) {
11628 arg_expr = source.CreateExpressionTree (ec);
11630 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11631 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11634 args.Add (new Argument (arg_expr));
11635 return CreateExpressionFactoryCall (ec, mname, args);
11638 protected override Expression DoResolve (ResolveContext ec)
11640 if (source == null)
11641 return EmptyExpressionStatement.Instance;
11643 if (!ResolveElement (ec))
11646 if (source is CollectionOrObjectInitializers) {
11647 target = target.Resolve (ec);
11648 if (target == null)
11651 Expression previous = ec.CurrentInitializerVariable;
11652 ec.CurrentInitializerVariable = target;
11653 source = source.Resolve (ec);
11654 ec.CurrentInitializerVariable = previous;
11655 if (source == null)
11658 eclass = source.eclass;
11659 type = source.Type;
11664 return base.DoResolve (ec);
11667 public override void EmitStatement (EmitContext ec)
11669 if (source is CollectionOrObjectInitializers)
11672 base.EmitStatement (ec);
11675 protected virtual bool ResolveElement (ResolveContext rc)
11677 var t = rc.CurrentInitializerVariable.Type;
11678 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11679 Arguments args = new Arguments (1);
11680 args.Add (new Argument (rc.CurrentInitializerVariable));
11681 target = new DynamicMemberBinder (Name, args, loc);
11683 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11684 if (member == null) {
11685 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11687 if (member != null) {
11688 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11689 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11694 if (member == null) {
11695 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11699 var me = member as MemberExpr;
11700 if (me is EventExpr) {
11701 me = me.ResolveMemberAccess (rc, null, null);
11702 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11703 rc.Report.Error (1913, loc,
11704 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11705 member.GetSignatureForError ());
11711 rc.Report.Error (1914, loc,
11712 "Static field or property `{0}' cannot be assigned in an object initializer",
11713 me.GetSignatureForError ());
11717 me.InstanceExpression = rc.CurrentInitializerVariable;
11725 // A collection initializer expression
11727 class CollectionElementInitializer : Invocation
11729 public class ElementInitializerArgument : Argument
11731 public ElementInitializerArgument (Expression e)
11737 sealed class AddMemberAccess : MemberAccess
11739 public AddMemberAccess (Expression expr, Location loc)
11740 : base (expr, "Add", loc)
11744 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11746 if (TypeManager.HasElementType (type))
11749 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11753 public CollectionElementInitializer (Expression argument)
11754 : base (null, new Arguments (1))
11756 base.arguments.Add (new ElementInitializerArgument (argument));
11757 this.loc = argument.Location;
11760 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11761 : base (null, new Arguments (arguments.Count))
11763 foreach (Expression e in arguments)
11764 base.arguments.Add (new ElementInitializerArgument (e));
11769 public CollectionElementInitializer (Location loc)
11770 : base (null, null)
11775 public override Expression CreateExpressionTree (ResolveContext ec)
11777 Arguments args = new Arguments (2);
11778 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11780 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11781 foreach (Argument a in arguments) {
11782 if (a.ArgType == Argument.AType.ExtensionType) {
11783 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11786 expr_initializers.Add (a.CreateExpressionTree (ec));
11789 args.Add (new Argument (new ArrayCreation (
11790 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11791 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11794 protected override void CloneTo (CloneContext clonectx, Expression t)
11796 CollectionElementInitializer target = (CollectionElementInitializer) t;
11797 if (arguments != null)
11798 target.arguments = arguments.Clone (clonectx);
11801 protected override Expression DoResolve (ResolveContext ec)
11803 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11805 return base.DoResolve (ec);
11809 class DictionaryElementInitializer : ElementInitializer
11811 readonly Arguments args;
11813 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11814 : base (null, initializer, loc)
11816 this.args = arguments;
11819 public override Expression CreateExpressionTree (ResolveContext ec)
11821 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11825 protected override bool ResolveElement (ResolveContext rc)
11827 var init = rc.CurrentInitializerVariable;
11828 var type = init.Type;
11830 if (type.IsArray) {
11831 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11835 if (type.IsPointer) {
11836 target = init.MakePointerAccess (rc, type, args);
11840 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11841 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11842 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11846 target = new IndexerExpr (indexers, type, init, args, loc);
11852 // A block of object or collection initializers
11854 public class CollectionOrObjectInitializers : ExpressionStatement
11856 IList<Expression> initializers;
11857 bool is_collection_initialization;
11859 public CollectionOrObjectInitializers (Location loc)
11860 : this (new Expression[0], loc)
11864 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11866 this.initializers = initializers;
11870 public IList<Expression> Initializers {
11872 return initializers;
11876 public bool IsEmpty {
11878 return initializers.Count == 0;
11882 public bool IsCollectionInitializer {
11884 return is_collection_initialization;
11888 protected override void CloneTo (CloneContext clonectx, Expression target)
11890 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11892 t.initializers = new List<Expression> (initializers.Count);
11893 foreach (var e in initializers)
11894 t.initializers.Add (e.Clone (clonectx));
11897 public override bool ContainsEmitWithAwait ()
11899 foreach (var e in initializers) {
11900 if (e.ContainsEmitWithAwait ())
11907 public override Expression CreateExpressionTree (ResolveContext ec)
11909 return CreateExpressionTree (ec, false);
11912 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11914 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11915 foreach (Expression e in initializers) {
11916 Expression expr = e.CreateExpressionTree (ec);
11918 expr_initializers.Add (expr);
11922 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11924 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11927 protected override Expression DoResolve (ResolveContext ec)
11929 List<string> element_names = null;
11930 for (int i = 0; i < initializers.Count; ++i) {
11931 Expression initializer = initializers [i];
11932 ElementInitializer element_initializer = initializer as ElementInitializer;
11935 if (element_initializer != null) {
11936 element_names = new List<string> (initializers.Count);
11937 if (!element_initializer.IsDictionaryInitializer)
11938 element_names.Add (element_initializer.Name);
11939 } else if (initializer is CompletingExpression) {
11940 initializer.Resolve (ec);
11941 throw new InternalErrorException ("This line should never be reached");
11943 var t = ec.CurrentInitializerVariable.Type;
11944 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11945 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11946 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11947 "object initializer because type `{1}' does not implement `{2}' interface",
11948 ec.CurrentInitializerVariable.GetSignatureForError (),
11949 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11950 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11953 is_collection_initialization = true;
11956 if (is_collection_initialization != (element_initializer == null)) {
11957 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11958 is_collection_initialization ? "collection initializer" : "object initializer");
11962 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11963 if (element_names.Contains (element_initializer.Name)) {
11964 ec.Report.Error (1912, element_initializer.Location,
11965 "An object initializer includes more than one member `{0}' initialization",
11966 element_initializer.Name);
11968 element_names.Add (element_initializer.Name);
11973 Expression e = initializer.Resolve (ec);
11974 if (e == EmptyExpressionStatement.Instance)
11975 initializers.RemoveAt (i--);
11977 initializers [i] = e;
11980 type = ec.CurrentInitializerVariable.Type;
11981 if (is_collection_initialization) {
11982 if (TypeManager.HasElementType (type)) {
11983 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11984 type.GetSignatureForError ());
11988 eclass = ExprClass.Variable;
11992 public override void Emit (EmitContext ec)
11994 EmitStatement (ec);
11997 public override void EmitStatement (EmitContext ec)
11999 foreach (ExpressionStatement e in initializers) {
12000 // TODO: need location region
12001 ec.Mark (e.Location);
12002 e.EmitStatement (ec);
12006 public override void FlowAnalysis (FlowAnalysisContext fc)
12008 foreach (var initializer in initializers) {
12009 if (initializer != null)
12010 initializer.FlowAnalysis (fc);
12016 // New expression with element/object initializers
12018 public class NewInitialize : New
12021 // This class serves as a proxy for variable initializer target instances.
12022 // A real variable is assigned later when we resolve left side of an
12025 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12027 NewInitialize new_instance;
12029 public InitializerTargetExpression (NewInitialize newInstance)
12031 this.type = newInstance.type;
12032 this.loc = newInstance.loc;
12033 this.eclass = newInstance.eclass;
12034 this.new_instance = newInstance;
12037 public override bool ContainsEmitWithAwait ()
12042 public override Expression CreateExpressionTree (ResolveContext ec)
12044 // Should not be reached
12045 throw new NotSupportedException ("ET");
12048 protected override Expression DoResolve (ResolveContext ec)
12053 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12058 public override void Emit (EmitContext ec)
12060 Expression e = (Expression) new_instance.instance;
12064 public override Expression EmitToField (EmitContext ec)
12066 return (Expression) new_instance.instance;
12069 #region IMemoryLocation Members
12071 public void AddressOf (EmitContext ec, AddressOp mode)
12073 new_instance.instance.AddressOf (ec, mode);
12079 CollectionOrObjectInitializers initializers;
12080 IMemoryLocation instance;
12081 DynamicExpressionStatement dynamic;
12083 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12084 : base (requested_type, arguments, l)
12086 this.initializers = initializers;
12089 public CollectionOrObjectInitializers Initializers {
12091 return initializers;
12095 protected override void CloneTo (CloneContext clonectx, Expression t)
12097 base.CloneTo (clonectx, t);
12099 NewInitialize target = (NewInitialize) t;
12100 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12103 public override bool ContainsEmitWithAwait ()
12105 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12108 public override Expression CreateExpressionTree (ResolveContext ec)
12110 Arguments args = new Arguments (2);
12111 args.Add (new Argument (base.CreateExpressionTree (ec)));
12112 if (!initializers.IsEmpty)
12113 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12115 return CreateExpressionFactoryCall (ec,
12116 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12120 protected override Expression DoResolve (ResolveContext ec)
12122 Expression e = base.DoResolve (ec);
12126 if (type.IsDelegate) {
12127 ec.Report.Error (1958, Initializers.Location,
12128 "Object and collection initializers cannot be used to instantiate a delegate");
12131 Expression previous = ec.CurrentInitializerVariable;
12132 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12133 initializers.Resolve (ec);
12134 ec.CurrentInitializerVariable = previous;
12136 dynamic = e as DynamicExpressionStatement;
12137 if (dynamic != null)
12143 public override void Emit (EmitContext ec)
12145 if (!CanEmitOptimizedLocalTarget (ec)) {
12146 var fe = ec.GetTemporaryField (type);
12148 if (!Emit (ec, fe))
12157 public override bool Emit (EmitContext ec, IMemoryLocation target)
12160 // Expression is initialized into temporary target then moved
12161 // to real one for atomicity
12163 IMemoryLocation temp_target = target;
12165 LocalTemporary temp = null;
12166 bool by_ref = false;
12167 if (!initializers.IsEmpty) {
12168 temp_target = target as LocalTemporary;
12169 if (temp_target == null)
12170 temp_target = target as StackFieldExpr;
12172 if (temp_target == null) {
12173 var vr = target as VariableReference;
12174 if (vr != null && vr.IsRef) {
12180 if (temp_target == null)
12181 temp_target = temp = new LocalTemporary (type);
12184 bool left_on_stack;
12185 if (dynamic != null) {
12187 left_on_stack = true;
12189 left_on_stack = base.Emit (ec, temp_target);
12192 if (initializers.IsEmpty)
12193 return left_on_stack;
12195 StackFieldExpr sf = null;
12197 // Move a new instance (reference-type) to local temporary variable
12198 if (left_on_stack) {
12200 temp_target = temp = new LocalTemporary (type);
12206 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12208 throw new NotImplementedException ();
12210 sf = ec.GetTemporaryField (type);
12211 sf.EmitAssign (ec, temp, false, false);
12214 left_on_stack = false;
12218 instance = temp_target;
12220 initializers.Emit (ec);
12222 ((Expression)temp_target).Emit (ec);
12228 sf.IsAvailableForReuse = true;
12233 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12235 return !(method == null && TypeSpec.IsValueType (type) &&
12236 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12237 initializers.ContainsEmitWithAwait ());
12240 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12242 instance = base.EmitAddressOf (ec, Mode);
12244 if (!initializers.IsEmpty)
12245 initializers.Emit (ec);
12250 public override void FlowAnalysis (FlowAnalysisContext fc)
12252 base.FlowAnalysis (fc);
12253 initializers.FlowAnalysis (fc);
12256 public override object Accept (StructuralVisitor visitor)
12258 return visitor.Visit (this);
12262 public class NewAnonymousType : New
12264 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12266 List<AnonymousTypeParameter> parameters;
12267 readonly TypeContainer parent;
12268 AnonymousTypeClass anonymous_type;
12270 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12271 : base (null, null, loc)
12273 this.parameters = parameters;
12274 this.parent = parent;
12277 public List<AnonymousTypeParameter> Parameters {
12279 return this.parameters;
12283 protected override void CloneTo (CloneContext clonectx, Expression target)
12285 if (parameters == null)
12288 NewAnonymousType t = (NewAnonymousType) target;
12289 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12290 foreach (AnonymousTypeParameter atp in parameters)
12291 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12294 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12296 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12300 type = AnonymousTypeClass.Create (parent, parameters, loc);
12304 int errors = ec.Report.Errors;
12305 type.CreateContainer ();
12306 type.DefineContainer ();
12308 if ((ec.Report.Errors - errors) == 0) {
12309 parent.Module.AddAnonymousType (type);
12310 type.PrepareEmit ();
12316 public override Expression CreateExpressionTree (ResolveContext ec)
12318 if (parameters == null)
12319 return base.CreateExpressionTree (ec);
12321 var init = new ArrayInitializer (parameters.Count, loc);
12322 foreach (var m in anonymous_type.Members) {
12323 var p = m as Property;
12325 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12328 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12329 foreach (Argument a in arguments)
12330 ctor_args.Add (a.CreateExpressionTree (ec));
12332 Arguments args = new Arguments (3);
12333 args.Add (new Argument (new TypeOfMethod (method, loc)));
12334 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12335 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12337 return CreateExpressionFactoryCall (ec, "New", args);
12340 protected override Expression DoResolve (ResolveContext ec)
12342 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12343 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12347 if (parameters == null) {
12348 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12349 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12350 return base.DoResolve (ec);
12353 bool error = false;
12354 arguments = new Arguments (parameters.Count);
12355 var t_args = new TypeSpec [parameters.Count];
12356 for (int i = 0; i < parameters.Count; ++i) {
12357 Expression e = parameters [i].Resolve (ec);
12363 arguments.Add (new Argument (e));
12364 t_args [i] = e.Type;
12370 anonymous_type = CreateAnonymousType (ec, parameters);
12371 if (anonymous_type == null)
12374 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12375 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12376 eclass = ExprClass.Value;
12380 public override object Accept (StructuralVisitor visitor)
12382 return visitor.Visit (this);
12386 public class AnonymousTypeParameter : ShimExpression
12388 public readonly string Name;
12390 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12391 : base (initializer)
12397 public AnonymousTypeParameter (Parameter parameter)
12398 : base (new SimpleName (parameter.Name, parameter.Location))
12400 this.Name = parameter.Name;
12401 this.loc = parameter.Location;
12404 public override bool Equals (object o)
12406 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12407 return other != null && Name == other.Name;
12410 public override int GetHashCode ()
12412 return Name.GetHashCode ();
12415 protected override Expression DoResolve (ResolveContext ec)
12417 Expression e = expr.Resolve (ec);
12421 if (e.eclass == ExprClass.MethodGroup) {
12422 Error_InvalidInitializer (ec, e.ExprClassName);
12427 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12428 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12435 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12437 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12438 Name, initializer);
12442 public class CatchFilterExpression : BooleanExpression
12444 public CatchFilterExpression (Expression expr, Location loc)
12451 public class InterpolatedString : Expression
12453 readonly StringLiteral start, end;
12454 List<Expression> interpolations;
12455 Arguments arguments;
12457 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12459 this.start = start;
12461 this.interpolations = interpolations;
12462 loc = start.Location;
12465 protected override void CloneTo (CloneContext clonectx, Expression t)
12467 InterpolatedString target = (InterpolatedString) t;
12469 if (interpolations != null) {
12470 target.interpolations = new List<Expression> ();
12471 foreach (var interpolation in interpolations) {
12472 target.interpolations.Add (interpolation.Clone (clonectx));
12477 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12479 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12480 if (factory == null)
12483 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12484 var res = new Invocation (ma, arguments).Resolve (rc);
12485 if (res != null && res.Type != type)
12486 res = Convert.ExplicitConversion (rc, res, type, loc);
12491 public override bool ContainsEmitWithAwait ()
12493 if (interpolations == null)
12496 foreach (var expr in interpolations) {
12497 if (expr.ContainsEmitWithAwait ())
12504 public override Expression CreateExpressionTree (ResolveContext rc)
12506 var best = ResolveBestFormatOverload (rc);
12510 Expression instance = new NullLiteral (loc);
12511 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12512 return CreateExpressionFactoryCall (rc, "Call", args);
12515 protected override Expression DoResolve (ResolveContext rc)
12519 if (interpolations == null) {
12521 arguments = new Arguments (1);
12523 arguments = new Arguments (interpolations.Count);
12525 var sb = new StringBuilder (start.Value);
12526 for (int i = 0; i < interpolations.Count; ++i) {
12528 sb.Append ('{').Append (i / 2);
12529 var isi = (InterpolatedStringInsert)interpolations [i];
12530 if (isi.Alignment != null) {
12532 var value = isi.ResolveAligment (rc);
12534 sb.Append (value.Value);
12537 if (isi.Format != null) {
12539 sb.Append (isi.Format);
12543 arguments.Add (new Argument (isi.Resolve (rc)));
12545 sb.Append (((StringLiteral)interpolations [i]).Value);
12549 sb.Append (end.Value);
12550 str = sb.ToString ();
12553 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12555 eclass = ExprClass.Value;
12556 type = rc.BuiltinTypes.String;
12560 public override void Emit (EmitContext ec)
12562 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12563 if (interpolations == null) {
12564 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12565 if (str != start.Value)
12566 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12573 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12577 var ca = new CallEmitter ();
12578 ca.Emit (ec, best, arguments, loc);
12581 public override void FlowAnalysis (FlowAnalysisContext fc)
12583 if (interpolations != null) {
12584 foreach (var expr in interpolations) {
12585 expr.FlowAnalysis (fc);
12590 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12592 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12593 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12594 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12598 public class InterpolatedStringInsert : CompositeExpression
12600 public InterpolatedStringInsert (Expression expr)
12605 public Expression Alignment { get; set; }
12606 public string Format { get; set; }
12608 protected override void CloneTo (CloneContext clonectx, Expression t)
12610 var target = (InterpolatedStringInsert)t;
12611 target.expr = expr.Clone (clonectx);
12612 if (Alignment != null)
12613 target.Alignment = Alignment.Clone (clonectx);
12616 protected override Expression DoResolve (ResolveContext rc)
12618 var expr = base.DoResolve (rc);
12623 // For better error reporting, assumes the built-in implementation uses object
12626 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12629 public override void FlowAnalysis (FlowAnalysisContext fc)
12631 Child.FlowAnalysis (fc);
12634 public int? ResolveAligment (ResolveContext rc)
12636 var c = Alignment.ResolveLabelConstant (rc);
12640 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12644 var value = (int) c.GetValueAsLong ();
12645 if (value > 32767 || value < -32767) {
12646 rc.Report.Warning (8094, 1, Alignment.Location,
12647 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");