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) {
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 override void FlowAnalysis (FlowAnalysisContext fc)
7610 if (arguments != null)
7611 arguments.FlowAnalysis (fc);
7614 public void AddressOf (EmitContext ec, AddressOp mode)
7616 EmitAddressOf (ec, mode);
7619 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7621 LocalTemporary value_target = new LocalTemporary (type);
7623 if (type is TypeParameterSpec) {
7624 DoEmitTypeParameter (ec);
7625 value_target.Store (ec);
7626 value_target.AddressOf (ec, mode);
7627 return value_target;
7630 value_target.AddressOf (ec, AddressOp.Store);
7632 if (method == null) {
7633 ec.Emit (OpCodes.Initobj, type);
7635 if (arguments != null)
7636 arguments.Emit (ec);
7638 ec.Emit (OpCodes.Call, method);
7641 value_target.AddressOf (ec, mode);
7642 return value_target;
7645 protected override void CloneTo (CloneContext clonectx, Expression t)
7647 New target = (New) t;
7649 target.RequestedType = RequestedType.Clone (clonectx);
7650 if (arguments != null){
7651 target.arguments = arguments.Clone (clonectx);
7655 public override SLE.Expression MakeExpression (BuilderContext ctx)
7658 return base.MakeExpression (ctx);
7660 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7664 public override object Accept (StructuralVisitor visitor)
7666 return visitor.Visit (this);
7671 // Array initializer expression, the expression is allowed in
7672 // variable or field initialization only which makes it tricky as
7673 // the type has to be infered based on the context either from field
7674 // type or variable type (think of multiple declarators)
7676 public class ArrayInitializer : Expression
7678 List<Expression> elements;
7679 BlockVariable variable;
7681 public ArrayInitializer (List<Expression> init, Location loc)
7687 public ArrayInitializer (int count, Location loc)
7688 : this (new List<Expression> (count), loc)
7692 public ArrayInitializer (Location loc)
7700 get { return elements.Count; }
7703 public List<Expression> Elements {
7709 public Expression this [int index] {
7711 return elements [index];
7715 public BlockVariable VariableDeclaration {
7726 public void Add (Expression expr)
7728 elements.Add (expr);
7731 public override bool ContainsEmitWithAwait ()
7733 throw new NotSupportedException ();
7736 public override Expression CreateExpressionTree (ResolveContext ec)
7738 throw new NotSupportedException ("ET");
7741 protected override void CloneTo (CloneContext clonectx, Expression t)
7743 var target = (ArrayInitializer) t;
7745 target.elements = new List<Expression> (elements.Count);
7746 foreach (var element in elements)
7747 target.elements.Add (element.Clone (clonectx));
7750 protected override Expression DoResolve (ResolveContext rc)
7752 var current_field = rc.CurrentMemberDefinition as FieldBase;
7753 TypeExpression type;
7754 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7755 type = new TypeExpression (current_field.MemberType, current_field.Location);
7756 } else if (variable != null) {
7757 if (variable.TypeExpression is VarExpr) {
7758 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7759 return EmptyExpression.Null;
7762 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7764 throw new NotImplementedException ("Unexpected array initializer context");
7767 return new ArrayCreation (type, this).Resolve (rc);
7770 public override void Emit (EmitContext ec)
7772 throw new InternalErrorException ("Missing Resolve call");
7775 public override void FlowAnalysis (FlowAnalysisContext fc)
7777 throw new InternalErrorException ("Missing Resolve call");
7780 public override object Accept (StructuralVisitor visitor)
7782 return visitor.Visit (this);
7787 /// 14.5.10.2: Represents an array creation expression.
7791 /// There are two possible scenarios here: one is an array creation
7792 /// expression that specifies the dimensions and optionally the
7793 /// initialization data and the other which does not need dimensions
7794 /// specified but where initialization data is mandatory.
7796 public class ArrayCreation : Expression
7798 FullNamedExpression requested_base_type;
7799 ArrayInitializer initializers;
7802 // The list of Argument types.
7803 // This is used to construct the `newarray' or constructor signature
7805 protected List<Expression> arguments;
7807 protected TypeSpec array_element_type;
7809 protected int dimensions;
7810 protected readonly ComposedTypeSpecifier rank;
7811 Expression first_emit;
7812 LocalTemporary first_emit_temp;
7814 protected List<Expression> array_data;
7816 Dictionary<int, int> bounds;
7819 // The number of constants in array initializers
7820 int const_initializers_count;
7821 bool only_constant_initializers;
7823 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7824 : this (requested_base_type, rank, initializers, l)
7826 arguments = new List<Expression> (exprs);
7827 num_arguments = arguments.Count;
7831 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7833 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7835 this.requested_base_type = requested_base_type;
7837 this.initializers = initializers;
7841 num_arguments = rank.Dimension;
7845 // For compiler generated single dimensional arrays only
7847 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7848 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7853 // For expressions like int[] foo = { 1, 2, 3 };
7855 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7856 : this (requested_base_type, null, initializers, initializers.Location)
7860 public ComposedTypeSpecifier Rank {
7866 public FullNamedExpression TypeExpression {
7868 return this.requested_base_type;
7872 public ArrayInitializer Initializers {
7874 return this.initializers;
7878 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7880 if (initializers != null && bounds == null) {
7882 // We use this to store all the data values in the order in which we
7883 // will need to store them in the byte blob later
7885 array_data = new List<Expression> (probe.Count);
7886 bounds = new Dictionary<int, int> ();
7889 if (specified_dims) {
7890 Expression a = arguments [idx];
7895 a = ConvertExpressionToArrayIndex (ec, a);
7901 if (initializers != null) {
7902 Constant c = a as Constant;
7903 if (c == null && a is ArrayIndexCast)
7904 c = ((ArrayIndexCast) a).Child as Constant;
7907 ec.Report.Error (150, a.Location, "A constant value is expected");
7913 value = System.Convert.ToInt32 (c.GetValue ());
7915 ec.Report.Error (150, a.Location, "A constant value is expected");
7919 // TODO: probe.Count does not fit ulong in
7920 if (value != probe.Count) {
7921 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7925 bounds[idx] = value;
7929 if (initializers == null)
7932 for (int i = 0; i < probe.Count; ++i) {
7934 if (o is ArrayInitializer) {
7935 var sub_probe = o as ArrayInitializer;
7936 if (idx + 1 >= dimensions){
7937 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7941 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7942 if (!bounds.ContainsKey(idx + 1))
7943 bounds[idx + 1] = sub_probe.Count;
7945 if (bounds[idx + 1] != sub_probe.Count) {
7946 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7950 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7953 } else if (child_bounds > 1) {
7954 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7956 Expression element = ResolveArrayElement (ec, o);
7957 if (element == null)
7960 // Initializers with the default values can be ignored
7961 Constant c = element as Constant;
7963 if (!c.IsDefaultInitializer (array_element_type)) {
7964 ++const_initializers_count;
7967 only_constant_initializers = false;
7970 array_data.Add (element);
7977 public override bool ContainsEmitWithAwait ()
7979 foreach (var arg in arguments) {
7980 if (arg.ContainsEmitWithAwait ())
7984 return InitializersContainAwait ();
7987 public override Expression CreateExpressionTree (ResolveContext ec)
7991 if (array_data == null) {
7992 args = new Arguments (arguments.Count + 1);
7993 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7994 foreach (Expression a in arguments)
7995 args.Add (new Argument (a.CreateExpressionTree (ec)));
7997 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8000 if (dimensions > 1) {
8001 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8005 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8006 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8007 if (array_data != null) {
8008 for (int i = 0; i < array_data.Count; ++i) {
8009 Expression e = array_data [i];
8010 args.Add (new Argument (e.CreateExpressionTree (ec)));
8014 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8017 void UpdateIndices (ResolveContext rc)
8020 for (var probe = initializers; probe != null;) {
8021 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8023 bounds[i++] = probe.Count;
8025 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8026 probe = (ArrayInitializer) probe[0];
8027 } else if (dimensions > i) {
8035 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8037 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8040 public override void FlowAnalysis (FlowAnalysisContext fc)
8042 foreach (var arg in arguments)
8043 arg.FlowAnalysis (fc);
8045 if (array_data != null) {
8046 foreach (var ad in array_data)
8047 ad.FlowAnalysis (fc);
8051 bool InitializersContainAwait ()
8053 if (array_data == null)
8056 foreach (var expr in array_data) {
8057 if (expr.ContainsEmitWithAwait ())
8064 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8066 element = element.Resolve (ec);
8067 if (element == null)
8070 if (element is CompoundAssign.TargetExpression) {
8071 if (first_emit != null)
8072 throw new InternalErrorException ("Can only handle one mutator at a time");
8073 first_emit = element;
8074 element = first_emit_temp = new LocalTemporary (element.Type);
8077 return Convert.ImplicitConversionRequired (
8078 ec, element, array_element_type, loc);
8081 protected bool ResolveInitializers (ResolveContext ec)
8084 only_constant_initializers = true;
8087 if (arguments != null) {
8089 for (int i = 0; i < arguments.Count; ++i) {
8090 res &= CheckIndices (ec, initializers, i, true, dimensions);
8091 if (initializers != null)
8098 arguments = new List<Expression> ();
8100 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8109 // Resolved the type of the array
8111 bool ResolveArrayType (ResolveContext ec)
8116 FullNamedExpression array_type_expr;
8117 if (num_arguments > 0) {
8118 array_type_expr = new ComposedCast (requested_base_type, rank);
8120 array_type_expr = requested_base_type;
8123 type = array_type_expr.ResolveAsType (ec);
8124 if (array_type_expr == null)
8127 var ac = type as ArrayContainer;
8129 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8133 array_element_type = ac.Element;
8134 dimensions = ac.Rank;
8139 protected override Expression DoResolve (ResolveContext ec)
8144 if (!ResolveArrayType (ec))
8148 // validate the initializers and fill in any missing bits
8150 if (!ResolveInitializers (ec))
8153 eclass = ExprClass.Value;
8157 byte [] MakeByteBlob ()
8162 int count = array_data.Count;
8164 TypeSpec element_type = array_element_type;
8165 if (element_type.IsEnum)
8166 element_type = EnumSpec.GetUnderlyingType (element_type);
8168 factor = BuiltinTypeSpec.GetSize (element_type);
8170 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8172 data = new byte [(count * factor + 3) & ~3];
8175 for (int i = 0; i < count; ++i) {
8176 var c = array_data[i] as Constant;
8182 object v = c.GetValue ();
8184 switch (element_type.BuiltinType) {
8185 case BuiltinTypeSpec.Type.Long:
8186 long lval = (long) v;
8188 for (int j = 0; j < factor; ++j) {
8189 data[idx + j] = (byte) (lval & 0xFF);
8193 case BuiltinTypeSpec.Type.ULong:
8194 ulong ulval = (ulong) v;
8196 for (int j = 0; j < factor; ++j) {
8197 data[idx + j] = (byte) (ulval & 0xFF);
8198 ulval = (ulval >> 8);
8201 case BuiltinTypeSpec.Type.Float:
8202 var fval = SingleConverter.SingleToInt32Bits((float) v);
8204 data[idx] = (byte) (fval & 0xff);
8205 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8206 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8207 data[idx + 3] = (byte) (fval >> 24);
8209 case BuiltinTypeSpec.Type.Double:
8210 element = BitConverter.GetBytes ((double) v);
8212 for (int j = 0; j < factor; ++j)
8213 data[idx + j] = element[j];
8215 // FIXME: Handle the ARM float format.
8216 if (!BitConverter.IsLittleEndian)
8217 System.Array.Reverse (data, idx, 8);
8219 case BuiltinTypeSpec.Type.Char:
8220 int chval = (int) ((char) v);
8222 data[idx] = (byte) (chval & 0xff);
8223 data[idx + 1] = (byte) (chval >> 8);
8225 case BuiltinTypeSpec.Type.Short:
8226 int sval = (int) ((short) v);
8228 data[idx] = (byte) (sval & 0xff);
8229 data[idx + 1] = (byte) (sval >> 8);
8231 case BuiltinTypeSpec.Type.UShort:
8232 int usval = (int) ((ushort) v);
8234 data[idx] = (byte) (usval & 0xff);
8235 data[idx + 1] = (byte) (usval >> 8);
8237 case BuiltinTypeSpec.Type.Int:
8240 data[idx] = (byte) (val & 0xff);
8241 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8242 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8243 data[idx + 3] = (byte) (val >> 24);
8245 case BuiltinTypeSpec.Type.UInt:
8246 uint uval = (uint) v;
8248 data[idx] = (byte) (uval & 0xff);
8249 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8250 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8251 data[idx + 3] = (byte) (uval >> 24);
8253 case BuiltinTypeSpec.Type.SByte:
8254 data[idx] = (byte) (sbyte) v;
8256 case BuiltinTypeSpec.Type.Byte:
8257 data[idx] = (byte) v;
8259 case BuiltinTypeSpec.Type.Bool:
8260 data[idx] = (byte) ((bool) v ? 1 : 0);
8262 case BuiltinTypeSpec.Type.Decimal:
8263 int[] bits = Decimal.GetBits ((decimal) v);
8266 // FIXME: For some reason, this doesn't work on the MS runtime.
8267 int[] nbits = new int[4];
8273 for (int j = 0; j < 4; j++) {
8274 data[p++] = (byte) (nbits[j] & 0xff);
8275 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8276 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8277 data[p++] = (byte) (nbits[j] >> 24);
8281 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8290 public override SLE.Expression MakeExpression (BuilderContext ctx)
8293 return base.MakeExpression (ctx);
8295 var initializers = new SLE.Expression [array_data.Count];
8296 for (var i = 0; i < initializers.Length; i++) {
8297 if (array_data [i] == null)
8298 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8300 initializers [i] = array_data [i].MakeExpression (ctx);
8303 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8308 // Emits the initializers for the array
8310 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8312 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8317 // First, the static data
8319 byte [] data = MakeByteBlob ();
8320 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8322 if (stackArray == null) {
8323 ec.Emit (OpCodes.Dup);
8325 stackArray.Emit (ec);
8328 ec.Emit (OpCodes.Ldtoken, fb);
8329 ec.Emit (OpCodes.Call, m);
8334 // Emits pieces of the array that can not be computed at compile
8335 // time (variables and string locations).
8337 // This always expect the top value on the stack to be the array
8339 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8341 int dims = bounds.Count;
8342 var current_pos = new int [dims];
8344 for (int i = 0; i < array_data.Count; i++){
8346 Expression e = array_data [i];
8347 var c = e as Constant;
8349 // Constant can be initialized via StaticInitializer
8350 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8354 if (stackArray != null) {
8355 if (e.ContainsEmitWithAwait ()) {
8356 e = e.EmitToField (ec);
8359 stackArray.EmitLoad (ec);
8361 ec.Emit (OpCodes.Dup);
8364 for (int idx = 0; idx < dims; idx++)
8365 ec.EmitInt (current_pos [idx]);
8368 // If we are dealing with a struct, get the
8369 // address of it, so we can store it.
8371 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8372 ec.Emit (OpCodes.Ldelema, etype);
8376 ec.EmitArrayStore ((ArrayContainer) type);
8382 for (int j = dims - 1; j >= 0; j--){
8384 if (current_pos [j] < bounds [j])
8386 current_pos [j] = 0;
8390 if (stackArray != null)
8391 stackArray.PrepareCleanup (ec);
8394 public override void Emit (EmitContext ec)
8396 var await_field = EmitToFieldSource (ec);
8397 if (await_field != null)
8398 await_field.Emit (ec);
8401 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8403 if (first_emit != null) {
8404 first_emit.Emit (ec);
8405 first_emit_temp.Store (ec);
8408 StackFieldExpr await_stack_field;
8409 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8410 await_stack_field = ec.GetTemporaryField (type);
8413 await_stack_field = null;
8416 EmitExpressionsList (ec, arguments);
8418 ec.EmitArrayNew ((ArrayContainer) type);
8420 if (initializers == null)
8421 return await_stack_field;
8423 if (await_stack_field != null)
8424 await_stack_field.EmitAssignFromStack (ec);
8428 // Emit static initializer for arrays which contain more than 2 items and
8429 // the static initializer will initialize at least 25% of array values or there
8430 // is more than 10 items to be initialized
8432 // NOTE: const_initializers_count does not contain default constant values.
8434 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8435 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8436 EmitStaticInitializers (ec, await_stack_field);
8438 if (!only_constant_initializers)
8439 EmitDynamicInitializers (ec, false, await_stack_field);
8443 EmitDynamicInitializers (ec, true, await_stack_field);
8446 if (first_emit_temp != null)
8447 first_emit_temp.Release (ec);
8449 return await_stack_field;
8452 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8454 // no multi dimensional or jagged arrays
8455 if (arguments.Count != 1 || array_element_type.IsArray) {
8456 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8460 // No array covariance, except for array -> object
8461 if (type != targetType) {
8462 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8463 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8467 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8468 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8473 // Single dimensional array of 0 size
8474 if (array_data == null) {
8475 IntConstant ic = arguments[0] as IntConstant;
8476 if (ic == null || !ic.IsDefaultValue) {
8477 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8485 enc.Encode (array_data.Count);
8486 foreach (var element in array_data) {
8487 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8491 protected override void CloneTo (CloneContext clonectx, Expression t)
8493 ArrayCreation target = (ArrayCreation) t;
8495 if (requested_base_type != null)
8496 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8498 if (arguments != null){
8499 target.arguments = new List<Expression> (arguments.Count);
8500 foreach (Expression e in arguments)
8501 target.arguments.Add (e.Clone (clonectx));
8504 if (initializers != null)
8505 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8508 public override object Accept (StructuralVisitor visitor)
8510 return visitor.Visit (this);
8515 // Represents an implicitly typed array epxression
8517 class ImplicitlyTypedArrayCreation : ArrayCreation
8519 TypeInferenceContext best_type_inference;
8521 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8522 : base (null, rank, initializers, loc)
8526 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8527 : base (null, initializers, loc)
8531 protected override Expression DoResolve (ResolveContext ec)
8536 dimensions = rank.Dimension;
8538 best_type_inference = new TypeInferenceContext ();
8540 if (!ResolveInitializers (ec))
8543 best_type_inference.FixAllTypes (ec);
8544 array_element_type = best_type_inference.InferredTypeArguments[0];
8545 best_type_inference = null;
8547 if (array_element_type == null ||
8548 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8549 arguments.Count != rank.Dimension) {
8550 ec.Report.Error (826, loc,
8551 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8556 // At this point we found common base type for all initializer elements
8557 // but we have to be sure that all static initializer elements are of
8560 UnifyInitializerElement (ec);
8562 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8563 eclass = ExprClass.Value;
8568 // Converts static initializer only
8570 void UnifyInitializerElement (ResolveContext ec)
8572 for (int i = 0; i < array_data.Count; ++i) {
8573 Expression e = array_data[i];
8575 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8579 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8581 element = element.Resolve (ec);
8582 if (element != null)
8583 best_type_inference.AddCommonTypeBound (element.Type);
8589 sealed class CompilerGeneratedThis : This
8591 public CompilerGeneratedThis (TypeSpec type, Location loc)
8597 protected override Expression DoResolve (ResolveContext rc)
8599 eclass = ExprClass.Variable;
8601 var block = rc.CurrentBlock;
8602 if (block != null) {
8603 var top = block.ParametersBlock.TopBlock;
8604 if (top.ThisVariable != null)
8605 variable_info = top.ThisVariable.VariableInfo;
8612 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8614 return DoResolve (rc);
8617 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8624 /// Represents the `this' construct
8627 public class This : VariableReference
8629 sealed class ThisVariable : ILocalVariable
8631 public static readonly ILocalVariable Instance = new ThisVariable ();
8633 public void Emit (EmitContext ec)
8638 public void EmitAssign (EmitContext ec)
8640 throw new InvalidOperationException ();
8643 public void EmitAddressOf (EmitContext ec)
8649 protected VariableInfo variable_info;
8651 public This (Location loc)
8658 public override string Name {
8659 get { return "this"; }
8662 public override bool IsLockedByStatement {
8670 public override bool IsRef {
8671 get { return type.IsStruct; }
8674 public override bool IsSideEffectFree {
8680 protected override ILocalVariable Variable {
8681 get { return ThisVariable.Instance; }
8684 public override VariableInfo VariableInfo {
8685 get { return variable_info; }
8688 public override bool IsFixed {
8689 get { return false; }
8694 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8697 // It's null for all cases when we don't need to check `this'
8698 // definitive assignment
8700 if (variable_info == null)
8703 if (fc.IsDefinitelyAssigned (variable_info))
8706 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8709 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8711 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8712 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8713 } else if (ec.CurrentAnonymousMethod != null) {
8714 ec.Report.Error (1673, loc,
8715 "Anonymous methods inside structs cannot access instance members of `this'. " +
8716 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8718 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8722 public override void FlowAnalysis (FlowAnalysisContext fc)
8724 CheckStructThisDefiniteAssignment (fc);
8727 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8732 AnonymousMethodStorey storey = ae.Storey;
8733 return storey != null ? storey.HoistedThis : null;
8736 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8738 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8741 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8744 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8750 public virtual void ResolveBase (ResolveContext ec)
8752 eclass = ExprClass.Variable;
8753 type = ec.CurrentType;
8755 if (!IsThisAvailable (ec, false)) {
8756 Error_ThisNotAvailable (ec);
8760 var block = ec.CurrentBlock;
8761 if (block != null) {
8762 var top = block.ParametersBlock.TopBlock;
8763 if (top.ThisVariable != null)
8764 variable_info = top.ThisVariable.VariableInfo;
8766 AnonymousExpression am = ec.CurrentAnonymousMethod;
8767 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8769 // Hoisted this is almost like hoisted variable but not exactly. When
8770 // there is no variable hoisted we can simply emit an instance method
8771 // without lifting this into a storey. Unfotunatelly this complicates
8772 // things in other cases because we don't know where this will be hoisted
8773 // until top-level block is fully resolved
8775 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8776 am.SetHasThisAccess ();
8781 protected override Expression DoResolve (ResolveContext ec)
8787 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8789 if (eclass == ExprClass.Unresolved)
8793 if (right_side == EmptyExpression.UnaryAddress)
8794 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8795 else if (right_side == EmptyExpression.OutAccess)
8796 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8798 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8804 public override int GetHashCode()
8806 throw new NotImplementedException ();
8809 public override bool Equals (object obj)
8811 This t = obj as This;
8818 protected override void CloneTo (CloneContext clonectx, Expression t)
8823 public override void SetHasAddressTaken ()
8828 public override object Accept (StructuralVisitor visitor)
8830 return visitor.Visit (this);
8835 /// Represents the `__arglist' construct
8837 public class ArglistAccess : Expression
8839 public ArglistAccess (Location loc)
8844 protected override void CloneTo (CloneContext clonectx, Expression target)
8849 public override bool ContainsEmitWithAwait ()
8854 public override Expression CreateExpressionTree (ResolveContext ec)
8856 throw new NotSupportedException ("ET");
8859 protected override Expression DoResolve (ResolveContext ec)
8861 eclass = ExprClass.Variable;
8862 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8864 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8865 ec.Report.Error (190, loc,
8866 "The __arglist construct is valid only within a variable argument method");
8872 public override void Emit (EmitContext ec)
8874 ec.Emit (OpCodes.Arglist);
8877 public override object Accept (StructuralVisitor visitor)
8879 return visitor.Visit (this);
8884 /// Represents the `__arglist (....)' construct
8886 public class Arglist : Expression
8888 Arguments arguments;
8890 public Arglist (Location loc)
8895 public Arglist (Arguments args, Location l)
8901 public Arguments Arguments {
8907 public MetaType[] ArgumentTypes {
8909 if (arguments == null)
8910 return MetaType.EmptyTypes;
8912 var retval = new MetaType[arguments.Count];
8913 for (int i = 0; i < retval.Length; i++)
8914 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8920 public override bool ContainsEmitWithAwait ()
8922 throw new NotImplementedException ();
8925 public override Expression CreateExpressionTree (ResolveContext ec)
8927 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8931 protected override Expression DoResolve (ResolveContext ec)
8933 eclass = ExprClass.Variable;
8934 type = InternalType.Arglist;
8935 if (arguments != null) {
8936 bool dynamic; // Can be ignored as there is always only 1 overload
8937 arguments.Resolve (ec, out dynamic);
8943 public override void Emit (EmitContext ec)
8945 if (arguments != null)
8946 arguments.Emit (ec);
8949 protected override void CloneTo (CloneContext clonectx, Expression t)
8951 Arglist target = (Arglist) t;
8953 if (arguments != null)
8954 target.arguments = arguments.Clone (clonectx);
8957 public override object Accept (StructuralVisitor visitor)
8959 return visitor.Visit (this);
8963 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8965 FullNamedExpression texpr;
8967 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8974 public FullNamedExpression TypeExpression {
8980 public override bool ContainsEmitWithAwait ()
8985 public void AddressOf (EmitContext ec, AddressOp mode)
8988 ec.Emit (OpCodes.Refanyval, type);
8991 protected override Expression DoResolve (ResolveContext rc)
8993 expr = expr.Resolve (rc);
8994 type = texpr.ResolveAsType (rc);
8995 if (expr == null || type == null)
8998 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8999 eclass = ExprClass.Variable;
9003 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9005 return DoResolve (rc);
9008 public override void Emit (EmitContext ec)
9011 ec.Emit (OpCodes.Refanyval, type);
9012 ec.EmitLoadFromPtr (type);
9015 public void Emit (EmitContext ec, bool leave_copy)
9017 throw new NotImplementedException ();
9020 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9023 ec.Emit (OpCodes.Refanyval, type);
9026 LocalTemporary temporary = null;
9028 ec.Emit (OpCodes.Dup);
9029 temporary = new LocalTemporary (source.Type);
9030 temporary.Store (ec);
9033 ec.EmitStoreFromPtr (type);
9035 if (temporary != null) {
9036 temporary.Emit (ec);
9037 temporary.Release (ec);
9041 public override object Accept (StructuralVisitor visitor)
9043 return visitor.Visit (this);
9047 public class RefTypeExpr : ShimExpression
9049 public RefTypeExpr (Expression expr, Location loc)
9055 protected override Expression DoResolve (ResolveContext rc)
9057 expr = expr.Resolve (rc);
9061 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9065 type = rc.BuiltinTypes.Type;
9066 eclass = ExprClass.Value;
9070 public override void Emit (EmitContext ec)
9073 ec.Emit (OpCodes.Refanytype);
9074 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9076 ec.Emit (OpCodes.Call, m);
9079 public override object Accept (StructuralVisitor visitor)
9081 return visitor.Visit (this);
9085 public class MakeRefExpr : ShimExpression
9087 public MakeRefExpr (Expression expr, Location loc)
9093 public override bool ContainsEmitWithAwait ()
9095 throw new NotImplementedException ();
9098 protected override Expression DoResolve (ResolveContext rc)
9100 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9101 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9102 eclass = ExprClass.Value;
9106 public override void Emit (EmitContext ec)
9108 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9109 ec.Emit (OpCodes.Mkrefany, expr.Type);
9112 public override object Accept (StructuralVisitor visitor)
9114 return visitor.Visit (this);
9119 /// Implements the typeof operator
9121 public class TypeOf : Expression {
9122 FullNamedExpression QueriedType;
9125 public TypeOf (FullNamedExpression queried_type, Location l)
9127 QueriedType = queried_type;
9132 // Use this constructor for any compiler generated typeof expression
9134 public TypeOf (TypeSpec type, Location loc)
9136 this.typearg = type;
9142 public override bool IsSideEffectFree {
9148 public TypeSpec TypeArgument {
9154 public FullNamedExpression TypeExpression {
9163 protected override void CloneTo (CloneContext clonectx, Expression t)
9165 TypeOf target = (TypeOf) t;
9166 if (QueriedType != null)
9167 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9170 public override bool ContainsEmitWithAwait ()
9175 public override Expression CreateExpressionTree (ResolveContext ec)
9177 Arguments args = new Arguments (2);
9178 args.Add (new Argument (this));
9179 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9180 return CreateExpressionFactoryCall (ec, "Constant", args);
9183 protected override Expression DoResolve (ResolveContext ec)
9185 if (eclass != ExprClass.Unresolved)
9188 if (typearg == null) {
9190 // Pointer types are allowed without explicit unsafe, they are just tokens
9192 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9193 typearg = QueriedType.ResolveAsType (ec, true);
9196 if (typearg == null)
9199 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9200 ec.Report.Error (1962, QueriedType.Location,
9201 "The typeof operator cannot be used on the dynamic type");
9205 type = ec.BuiltinTypes.Type;
9207 // Even though what is returned is a type object, it's treated as a value by the compiler.
9208 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9209 eclass = ExprClass.Value;
9213 static bool ContainsDynamicType (TypeSpec type)
9215 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9218 var element_container = type as ElementTypeSpec;
9219 if (element_container != null)
9220 return ContainsDynamicType (element_container.Element);
9222 foreach (var t in type.TypeArguments) {
9223 if (ContainsDynamicType (t)) {
9231 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9233 // Target type is not System.Type therefore must be object
9234 // and we need to use different encoding sequence
9235 if (targetType != type)
9238 if (typearg is InflatedTypeSpec) {
9241 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9242 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9243 typearg.GetSignatureForError ());
9247 gt = gt.DeclaringType;
9248 } while (gt != null);
9251 if (ContainsDynamicType (typearg)) {
9252 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9256 enc.EncodeTypeName (typearg);
9259 public override void Emit (EmitContext ec)
9261 ec.Emit (OpCodes.Ldtoken, typearg);
9262 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9264 ec.Emit (OpCodes.Call, m);
9267 public override object Accept (StructuralVisitor visitor)
9269 return visitor.Visit (this);
9273 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9275 public TypeOfMethod (MethodSpec method, Location loc)
9276 : base (method, loc)
9280 protected override Expression DoResolve (ResolveContext ec)
9282 if (member.IsConstructor) {
9283 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9285 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9291 return base.DoResolve (ec);
9294 public override void Emit (EmitContext ec)
9296 ec.Emit (OpCodes.Ldtoken, member);
9299 ec.Emit (OpCodes.Castclass, type);
9302 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9304 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9307 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9309 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9313 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9315 protected readonly T member;
9317 protected TypeOfMember (T member, Location loc)
9319 this.member = member;
9323 public override bool IsSideEffectFree {
9329 public override bool ContainsEmitWithAwait ()
9334 public override Expression CreateExpressionTree (ResolveContext ec)
9336 Arguments args = new Arguments (2);
9337 args.Add (new Argument (this));
9338 args.Add (new Argument (new TypeOf (type, loc)));
9339 return CreateExpressionFactoryCall (ec, "Constant", args);
9342 protected override Expression DoResolve (ResolveContext ec)
9344 eclass = ExprClass.Value;
9348 public override void Emit (EmitContext ec)
9350 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9351 PredefinedMember<MethodSpec> p;
9353 p = GetTypeFromHandleGeneric (ec);
9354 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9356 p = GetTypeFromHandle (ec);
9359 var mi = p.Resolve (loc);
9361 ec.Emit (OpCodes.Call, mi);
9364 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9365 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9368 sealed class TypeOfField : TypeOfMember<FieldSpec>
9370 public TypeOfField (FieldSpec field, Location loc)
9375 protected override Expression DoResolve (ResolveContext ec)
9377 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9381 return base.DoResolve (ec);
9384 public override void Emit (EmitContext ec)
9386 ec.Emit (OpCodes.Ldtoken, member);
9390 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9392 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9395 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9397 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9402 /// Implements the sizeof expression
9404 public class SizeOf : Expression {
9405 readonly Expression texpr;
9406 TypeSpec type_queried;
9408 public SizeOf (Expression queried_type, Location l)
9410 this.texpr = queried_type;
9414 public override bool IsSideEffectFree {
9420 public Expression TypeExpression {
9426 public override bool ContainsEmitWithAwait ()
9431 public override Expression CreateExpressionTree (ResolveContext ec)
9433 Error_PointerInsideExpressionTree (ec);
9437 protected override Expression DoResolve (ResolveContext ec)
9439 type_queried = texpr.ResolveAsType (ec);
9440 if (type_queried == null)
9443 if (type_queried.IsEnum)
9444 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9446 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9448 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9451 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9456 ec.Report.Error (233, loc,
9457 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9458 type_queried.GetSignatureForError ());
9461 type = ec.BuiltinTypes.Int;
9462 eclass = ExprClass.Value;
9466 public override void Emit (EmitContext ec)
9468 ec.Emit (OpCodes.Sizeof, type_queried);
9471 protected override void CloneTo (CloneContext clonectx, Expression t)
9475 public override object Accept (StructuralVisitor visitor)
9477 return visitor.Visit (this);
9482 /// Implements the qualified-alias-member (::) expression.
9484 public class QualifiedAliasMember : MemberAccess
9486 readonly string alias;
9487 public static readonly string GlobalAlias = "global";
9489 public QualifiedAliasMember (string alias, string identifier, Location l)
9490 : base (null, identifier, l)
9495 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9496 : base (null, identifier, targs, l)
9501 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9502 : base (null, identifier, arity, l)
9507 public string Alias {
9513 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9515 if (alias == GlobalAlias)
9516 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9518 int errors = mc.Module.Compiler.Report.Errors;
9519 var expr = mc.LookupNamespaceAlias (alias);
9521 if (errors == mc.Module.Compiler.Report.Errors)
9522 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9530 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9532 expr = CreateExpressionFromAlias (mc);
9536 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9539 protected override Expression DoResolve (ResolveContext rc)
9541 return ResolveAsTypeOrNamespace (rc, false);
9544 public override string GetSignatureForError ()
9547 if (targs != null) {
9548 name = Name + "<" + targs.GetSignatureForError () + ">";
9551 return alias + "::" + name;
9554 public override bool HasConditionalAccess ()
9559 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9561 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9562 rc.Module.Compiler.Report.Error (687, loc,
9563 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9564 GetSignatureForError ());
9569 return DoResolve (rc);
9572 protected override void CloneTo (CloneContext clonectx, Expression t)
9577 public override object Accept (StructuralVisitor visitor)
9579 return visitor.Visit (this);
9584 /// Implements the member access expression
9586 public class MemberAccess : ATypeNameExpression
9588 protected Expression expr;
9590 public MemberAccess (Expression expr, string id)
9591 : base (id, expr.Location)
9596 public MemberAccess (Expression expr, string identifier, Location loc)
9597 : base (identifier, loc)
9602 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9603 : base (identifier, args, loc)
9608 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9609 : base (identifier, arity, loc)
9614 public Expression LeftExpression {
9620 public override Location StartLocation {
9622 return expr == null ? loc : expr.StartLocation;
9626 protected override Expression DoResolve (ResolveContext rc)
9628 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9630 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9635 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9637 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9639 if (e is TypeExpr) {
9640 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9645 e = e.ResolveLValue (rc, rhs);
9650 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9652 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9653 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9655 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9658 public override bool HasConditionalAccess ()
9660 return LeftExpression.HasConditionalAccess ();
9663 public static bool IsValidDotExpression (TypeSpec type)
9665 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9666 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9668 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9671 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9673 var sn = expr as SimpleName;
9674 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9677 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9680 // Resolve expression which does have type set as we need expression type
9681 // with disable flow analysis as we don't know whether left side expression
9682 // is used as variable or type
9684 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9685 expr = expr.Resolve (rc);
9686 } else if (expr is TypeParameterExpr) {
9687 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9691 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9692 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9693 expr = expr.Resolve (rc, flags);
9696 expr = expr.Resolve (rc, flags);
9703 var ns = expr as NamespaceExpression;
9705 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9707 if (retval == null) {
9708 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9713 if (HasTypeArguments)
9714 return new GenericTypeExpr (retval.Type, targs, loc);
9716 targs.Resolve (rc, false);
9722 var cma = this as ConditionalMemberAccess;
9725 TypeSpec expr_type = expr.Type;
9726 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9727 me = expr as MemberExpr;
9729 me.ResolveInstanceExpression (rc, null);
9731 Arguments args = new Arguments (1);
9732 args.Add (new Argument (expr));
9735 return new DynamicConditionalMemberBinder (Name, args, loc);
9737 return new DynamicMemberBinder (Name, args, loc);
9741 if (!IsNullPropagatingValid (expr.Type)) {
9742 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9746 if (expr_type.IsNullableType) {
9747 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9748 expr_type = expr.Type;
9752 if (!IsValidDotExpression (expr_type)) {
9753 Error_OperatorCannotBeApplied (rc, expr_type);
9757 var lookup_arity = Arity;
9758 bool errorMode = false;
9759 Expression member_lookup;
9761 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9762 if (member_lookup == null) {
9764 // Try to look for extension method when member lookup failed
9766 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9767 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9768 if (methods != null) {
9769 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9770 if (HasTypeArguments) {
9771 if (!targs.Resolve (rc, false))
9774 emg.SetTypeArguments (rc, targs);
9778 emg.ConditionalAccess = true;
9780 // TODO: it should really skip the checks bellow
9781 return emg.Resolve (rc);
9787 if (member_lookup == null) {
9788 var dep = expr_type.GetMissingDependencies ();
9790 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9791 } else if (expr is TypeExpr) {
9792 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9794 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9800 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9801 // Leave it to overload resolution to report correct error
9802 } else if (!(member_lookup is TypeExpr)) {
9803 // TODO: rc.SymbolRelatedToPreviousError
9804 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9809 if (member_lookup != null)
9813 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9817 TypeExpr texpr = member_lookup as TypeExpr;
9818 if (texpr != null) {
9819 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9820 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9821 Name, texpr.GetSignatureForError ());
9824 if (!texpr.Type.IsAccessible (rc)) {
9825 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9826 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9830 if (HasTypeArguments) {
9831 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9834 return member_lookup;
9837 me = member_lookup as MemberExpr;
9839 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9844 me.ConditionalAccess = true;
9847 me = me.ResolveMemberAccess (rc, expr, sn);
9850 if (!targs.Resolve (rc, false))
9853 me.SetTypeArguments (rc, targs);
9859 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9861 FullNamedExpression fexpr = expr as FullNamedExpression;
9862 if (fexpr == null) {
9863 expr.ResolveAsType (rc);
9867 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9869 if (expr_resolved == null)
9872 var ns = expr_resolved as NamespaceExpression;
9874 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9876 if (retval == null) {
9877 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9878 } else if (Arity > 0) {
9879 if (HasTypeArguments) {
9880 retval = new GenericTypeExpr (retval.Type, targs, loc);
9881 if (retval.ResolveAsType (rc) == null)
9884 targs.Resolve (rc, allowUnboundTypeArguments);
9886 retval = new GenericOpenTypeExpr (retval.Type, loc);
9893 var tnew_expr = expr_resolved.ResolveAsType (rc);
9894 if (tnew_expr == null)
9897 TypeSpec expr_type = tnew_expr;
9898 if (TypeManager.IsGenericParameter (expr_type)) {
9899 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9900 tnew_expr.GetSignatureForError ());
9904 var qam = this as QualifiedAliasMember;
9906 rc.Module.Compiler.Report.Error (431, loc,
9907 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9912 TypeSpec nested = null;
9913 while (expr_type != null) {
9914 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9915 if (nested == null) {
9916 if (expr_type == tnew_expr) {
9917 Error_IdentifierNotFound (rc, expr_type);
9921 expr_type = tnew_expr;
9922 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9923 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9927 if (nested.IsAccessible (rc))
9931 // Keep looking after inaccessible candidate but only if
9932 // we are not in same context as the definition itself
9934 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9937 expr_type = expr_type.BaseType;
9942 if (HasTypeArguments) {
9943 texpr = new GenericTypeExpr (nested, targs, loc);
9945 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9947 texpr = new GenericOpenTypeExpr (nested, loc);
9949 } else if (expr_resolved is GenericOpenTypeExpr) {
9950 texpr = new GenericOpenTypeExpr (nested, loc);
9952 texpr = new TypeExpression (nested, loc);
9955 if (texpr.ResolveAsType (rc) == null)
9961 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9963 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9965 if (nested != null) {
9966 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9970 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9971 if (any_other_member != null) {
9972 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9976 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9977 Name, expr_type.GetSignatureForError ());
9980 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9982 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9985 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9987 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9988 ec.Report.SymbolRelatedToPreviousError (type);
9990 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9992 // a using directive or an assembly reference
9994 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9996 missing = "an assembly reference";
9999 ec.Report.Error (1061, loc,
10000 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10001 type.GetSignatureForError (), name, missing);
10005 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10008 public override string GetSignatureForError ()
10010 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10013 protected override void CloneTo (CloneContext clonectx, Expression t)
10015 MemberAccess target = (MemberAccess) t;
10017 target.expr = expr.Clone (clonectx);
10020 public override object Accept (StructuralVisitor visitor)
10022 return visitor.Visit (this);
10026 public class ConditionalMemberAccess : MemberAccess
10028 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10029 : base (expr, identifier, args, loc)
10033 public override bool HasConditionalAccess ()
10040 /// Implements checked expressions
10042 public class CheckedExpr : Expression {
10044 public Expression Expr;
10046 public CheckedExpr (Expression e, Location l)
10052 public override bool ContainsEmitWithAwait ()
10054 return Expr.ContainsEmitWithAwait ();
10057 public override Expression CreateExpressionTree (ResolveContext ec)
10059 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10060 return Expr.CreateExpressionTree (ec);
10063 protected override Expression DoResolve (ResolveContext ec)
10065 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10066 Expr = Expr.Resolve (ec);
10071 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10074 eclass = Expr.eclass;
10079 public override void Emit (EmitContext ec)
10081 using (ec.With (EmitContext.Options.CheckedScope, true))
10085 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10087 using (ec.With (EmitContext.Options.CheckedScope, true))
10088 Expr.EmitBranchable (ec, target, on_true);
10091 public override void FlowAnalysis (FlowAnalysisContext fc)
10093 Expr.FlowAnalysis (fc);
10096 public override SLE.Expression MakeExpression (BuilderContext ctx)
10098 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10099 return Expr.MakeExpression (ctx);
10103 protected override void CloneTo (CloneContext clonectx, Expression t)
10105 CheckedExpr target = (CheckedExpr) t;
10107 target.Expr = Expr.Clone (clonectx);
10110 public override object Accept (StructuralVisitor visitor)
10112 return visitor.Visit (this);
10117 /// Implements the unchecked expression
10119 public class UnCheckedExpr : Expression {
10121 public Expression Expr;
10123 public UnCheckedExpr (Expression e, Location l)
10129 public override bool ContainsEmitWithAwait ()
10131 return Expr.ContainsEmitWithAwait ();
10134 public override Expression CreateExpressionTree (ResolveContext ec)
10136 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10137 return Expr.CreateExpressionTree (ec);
10140 protected override Expression DoResolve (ResolveContext ec)
10142 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10143 Expr = Expr.Resolve (ec);
10148 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10151 eclass = Expr.eclass;
10156 public override void Emit (EmitContext ec)
10158 using (ec.With (EmitContext.Options.CheckedScope, false))
10162 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10164 using (ec.With (EmitContext.Options.CheckedScope, false))
10165 Expr.EmitBranchable (ec, target, on_true);
10168 public override void FlowAnalysis (FlowAnalysisContext fc)
10170 Expr.FlowAnalysis (fc);
10173 protected override void CloneTo (CloneContext clonectx, Expression t)
10175 UnCheckedExpr target = (UnCheckedExpr) t;
10177 target.Expr = Expr.Clone (clonectx);
10180 public override object Accept (StructuralVisitor visitor)
10182 return visitor.Visit (this);
10187 /// An Element Access expression.
10189 /// During semantic analysis these are transformed into
10190 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10192 public class ElementAccess : Expression
10194 public Arguments Arguments;
10195 public Expression Expr;
10196 bool conditional_access_receiver;
10198 public ElementAccess (Expression e, Arguments args, Location loc)
10202 this.Arguments = args;
10205 public bool ConditionalAccess { get; set; }
10207 public override Location StartLocation {
10209 return Expr.StartLocation;
10213 public override bool ContainsEmitWithAwait ()
10215 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10219 // We perform some simple tests, and then to "split" the emit and store
10220 // code we create an instance of a different class, and return that.
10222 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10224 if (conditionalAccessReceiver)
10225 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10227 Expr = Expr.Resolve (ec);
10229 if (conditionalAccessReceiver)
10230 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10237 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10238 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10242 if (type.IsArray) {
10243 var aa = new ArrayAccess (this, loc) {
10244 ConditionalAccess = ConditionalAccess,
10247 if (conditionalAccessReceiver)
10248 aa.SetConditionalAccessReceiver ();
10253 if (type.IsPointer)
10254 return Expr.MakePointerAccess (ec, type, Arguments);
10256 FieldExpr fe = Expr as FieldExpr;
10258 var ff = fe.Spec as FixedFieldSpec;
10260 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10264 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10265 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10266 var indexer = new IndexerExpr (indexers, type, this) {
10267 ConditionalAccess = ConditionalAccess
10270 if (conditionalAccessReceiver)
10271 indexer.SetConditionalAccessReceiver ();
10276 Error_CannotApplyIndexing (ec, type, loc);
10281 public override Expression CreateExpressionTree (ResolveContext ec)
10283 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10284 Expr.CreateExpressionTree (ec));
10286 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10289 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10291 if (type != InternalType.ErrorType) {
10292 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10293 type.GetSignatureForError ());
10297 public override bool HasConditionalAccess ()
10299 return ConditionalAccess || Expr.HasConditionalAccess ();
10302 void ResolveConditionalAccessReceiver (ResolveContext rc)
10304 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10305 conditional_access_receiver = true;
10309 protected override Expression DoResolve (ResolveContext rc)
10311 ResolveConditionalAccessReceiver (rc);
10313 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10317 return expr.Resolve (rc);
10320 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10322 var res = CreateAccessExpression (ec, false);
10326 return res.ResolveLValue (ec, rhs);
10329 public override void Emit (EmitContext ec)
10331 throw new Exception ("Should never be reached");
10334 public override void FlowAnalysis (FlowAnalysisContext fc)
10336 Expr.FlowAnalysis (fc);
10338 Arguments.FlowAnalysis (fc);
10341 public override string GetSignatureForError ()
10343 return Expr.GetSignatureForError ();
10346 protected override void CloneTo (CloneContext clonectx, Expression t)
10348 ElementAccess target = (ElementAccess) t;
10350 target.Expr = Expr.Clone (clonectx);
10351 if (Arguments != null)
10352 target.Arguments = Arguments.Clone (clonectx);
10355 public override object Accept (StructuralVisitor visitor)
10357 return visitor.Visit (this);
10362 /// Implements array access
10364 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10366 // Points to our "data" repository
10370 LocalTemporary temp;
10372 bool? has_await_args;
10373 bool conditional_access_receiver;
10375 public ArrayAccess (ElementAccess ea_data, Location l)
10381 public bool ConditionalAccess { get; set; }
10383 public void AddressOf (EmitContext ec, AddressOp mode)
10385 var ac = (ArrayContainer) ea.Expr.Type;
10387 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10388 LoadInstanceAndArguments (ec, false, true);
10391 LoadInstanceAndArguments (ec, false, false);
10393 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10394 ec.Emit (OpCodes.Readonly);
10396 ec.EmitArrayAddress (ac);
10399 public override Expression CreateExpressionTree (ResolveContext ec)
10401 if (ConditionalAccess)
10402 Error_NullShortCircuitInsideExpressionTree (ec);
10404 return ea.CreateExpressionTree (ec);
10407 public override bool ContainsEmitWithAwait ()
10409 return ea.ContainsEmitWithAwait ();
10412 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10414 if (HasConditionalAccess ())
10415 Error_NullPropagatingLValue (ec);
10417 return DoResolve (ec);
10420 protected override Expression DoResolve (ResolveContext ec)
10422 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10424 ea.Arguments.Resolve (ec, out dynamic);
10426 var ac = ea.Expr.Type as ArrayContainer;
10427 int rank = ea.Arguments.Count;
10428 if (ac.Rank != rank) {
10429 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10430 rank.ToString (), ac.Rank.ToString ());
10435 if (type.IsPointer && !ec.IsUnsafe) {
10436 UnsafeError (ec, ea.Location);
10439 if (conditional_access_receiver)
10440 type = LiftMemberType (ec, type);
10442 foreach (Argument a in ea.Arguments) {
10443 var na = a as NamedArgument;
10445 ElementAccess.Error_NamedArgument (na, ec.Report);
10447 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10450 eclass = ExprClass.Variable;
10455 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10457 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10460 public override void FlowAnalysis (FlowAnalysisContext fc)
10462 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10464 ea.FlowAnalysis (fc);
10466 if (conditional_access_receiver)
10467 fc.DefiniteAssignment = da;
10470 public override bool HasConditionalAccess ()
10472 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10476 // Load the array arguments into the stack.
10478 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10480 if (prepareAwait) {
10481 ea.Expr = ea.Expr.EmitToField (ec);
10483 var ie = new InstanceEmitter (ea.Expr, false);
10484 ie.Emit (ec, ConditionalAccess);
10486 if (duplicateArguments) {
10487 ec.Emit (OpCodes.Dup);
10489 var copy = new LocalTemporary (ea.Expr.Type);
10495 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10496 if (dup_args != null)
10497 ea.Arguments = dup_args;
10500 public void Emit (EmitContext ec, bool leave_copy)
10503 ec.EmitLoadFromPtr (type);
10505 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10506 LoadInstanceAndArguments (ec, false, true);
10509 if (conditional_access_receiver)
10510 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10512 var ac = (ArrayContainer) ea.Expr.Type;
10513 LoadInstanceAndArguments (ec, false, false);
10514 ec.EmitArrayLoad (ac);
10516 if (conditional_access_receiver)
10517 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10521 ec.Emit (OpCodes.Dup);
10522 temp = new LocalTemporary (this.type);
10527 public override void Emit (EmitContext ec)
10532 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10534 var ac = (ArrayContainer) ea.Expr.Type;
10535 TypeSpec t = source.Type;
10537 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10540 // When we are dealing with a struct, get the address of it to avoid value copy
10541 // Same cannot be done for reference type because array covariance and the
10542 // check in ldelema requires to specify the type of array element stored at the index
10544 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10545 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10547 if (has_await_args.Value) {
10548 if (source.ContainsEmitWithAwait ()) {
10549 source = source.EmitToField (ec);
10550 isCompound = false;
10554 LoadInstanceAndArguments (ec, isCompound, false);
10559 ec.EmitArrayAddress (ac);
10562 ec.Emit (OpCodes.Dup);
10566 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10568 if (has_await_args.Value) {
10569 if (source.ContainsEmitWithAwait ())
10570 source = source.EmitToField (ec);
10572 LoadInstanceAndArguments (ec, false, false);
10579 var lt = ea.Expr as LocalTemporary;
10585 ec.Emit (OpCodes.Dup);
10586 temp = new LocalTemporary (this.type);
10591 ec.EmitStoreFromPtr (t);
10593 ec.EmitArrayStore (ac);
10596 if (temp != null) {
10602 public override Expression EmitToField (EmitContext ec)
10605 // Have to be specialized for arrays to get access to
10606 // underlying element. Instead of another result copy we
10607 // need direct access to element
10611 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10613 ea.Expr = ea.Expr.EmitToField (ec);
10614 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10618 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10620 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10623 public override SLE.Expression MakeExpression (BuilderContext ctx)
10625 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10628 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10630 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10631 return Arguments.MakeExpression (ea.Arguments, ctx);
10635 public void SetConditionalAccessReceiver ()
10637 conditional_access_receiver = true;
10642 // Indexer access expression
10644 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10646 IList<MemberSpec> indexers;
10647 Arguments arguments;
10648 TypeSpec queried_type;
10650 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10651 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10655 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10658 this.indexers = indexers;
10659 this.queried_type = queriedType;
10660 this.InstanceExpression = instance;
10661 this.arguments = args;
10666 protected override Arguments Arguments {
10675 protected override TypeSpec DeclaringType {
10677 return best_candidate.DeclaringType;
10681 public override bool IsInstance {
10687 public override bool IsStatic {
10693 public override string KindName {
10694 get { return "indexer"; }
10697 public override string Name {
10705 public override bool ContainsEmitWithAwait ()
10707 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10710 public override Expression CreateExpressionTree (ResolveContext ec)
10712 if (ConditionalAccess) {
10713 Error_NullShortCircuitInsideExpressionTree (ec);
10716 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10717 InstanceExpression.CreateExpressionTree (ec),
10718 new TypeOfMethod (Getter, loc));
10720 return CreateExpressionFactoryCall (ec, "Call", args);
10723 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10725 LocalTemporary await_source_arg = null;
10728 emitting_compound_assignment = true;
10729 if (source is DynamicExpressionStatement) {
10734 emitting_compound_assignment = false;
10736 if (has_await_arguments) {
10737 await_source_arg = new LocalTemporary (Type);
10738 await_source_arg.Store (ec);
10740 arguments.Add (new Argument (await_source_arg));
10743 temp = await_source_arg;
10746 has_await_arguments = false;
10751 ec.Emit (OpCodes.Dup);
10752 temp = new LocalTemporary (Type);
10758 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10759 source = source.EmitToField (ec);
10761 temp = new LocalTemporary (Type);
10768 arguments.Add (new Argument (source));
10771 var call = new CallEmitter ();
10772 call.InstanceExpression = InstanceExpression;
10773 if (arguments == null)
10774 call.InstanceExpressionOnStack = true;
10776 call.Emit (ec, Setter, arguments, loc);
10778 if (temp != null) {
10781 } else if (leave_copy) {
10785 if (await_source_arg != null) {
10786 await_source_arg.Release (ec);
10790 public override void FlowAnalysis (FlowAnalysisContext fc)
10792 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10794 base.FlowAnalysis (fc);
10795 arguments.FlowAnalysis (fc);
10797 if (conditional_access_receiver)
10798 fc.DefiniteAssignment = da;
10801 public override string GetSignatureForError ()
10803 return best_candidate.GetSignatureForError ();
10806 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10809 throw new NotSupportedException ();
10811 var value = new[] { source.MakeExpression (ctx) };
10812 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10813 return SLE.Expression.Block (
10814 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10819 public override SLE.Expression MakeExpression (BuilderContext ctx)
10822 return base.MakeExpression (ctx);
10824 var args = Arguments.MakeExpression (arguments, ctx);
10825 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10829 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10831 if (best_candidate != null)
10834 eclass = ExprClass.IndexerAccess;
10837 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10838 arguments.Resolve (rc, out dynamic);
10841 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10844 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10845 res.BaseMembersProvider = this;
10846 res.InstanceQualifier = this;
10848 // TODO: Do I need 2 argument sets?
10849 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10850 if (best_candidate != null)
10851 type = res.BestCandidateReturnType;
10852 else if (!res.BestCandidateIsDynamic)
10857 // It has dynamic arguments
10860 Arguments args = new Arguments (arguments.Count + 1);
10862 rc.Report.Error (1972, loc,
10863 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10865 args.Add (new Argument (InstanceExpression));
10867 args.AddRange (arguments);
10869 best_candidate = null;
10870 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
10874 // Try to avoid resolving left expression again
10876 if (right_side != null)
10877 ResolveInstanceExpression (rc, right_side);
10882 protected override void CloneTo (CloneContext clonectx, Expression t)
10884 IndexerExpr target = (IndexerExpr) t;
10886 if (arguments != null)
10887 target.arguments = arguments.Clone (clonectx);
10890 public void SetConditionalAccessReceiver ()
10892 conditional_access_receiver = true;
10895 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10897 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10900 #region IBaseMembersProvider Members
10902 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10904 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10907 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10909 if (queried_type == member.DeclaringType)
10912 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10913 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10916 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10925 // A base access expression
10927 public class BaseThis : This
10929 public BaseThis (Location loc)
10934 public BaseThis (TypeSpec type, Location loc)
10938 eclass = ExprClass.Variable;
10943 public override string Name {
10951 public override Expression CreateExpressionTree (ResolveContext ec)
10953 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10954 return base.CreateExpressionTree (ec);
10957 public override void Emit (EmitContext ec)
10961 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10962 var context_type = ec.CurrentType;
10963 ec.Emit (OpCodes.Ldobj, context_type);
10964 ec.Emit (OpCodes.Box, context_type);
10968 protected override void Error_ThisNotAvailable (ResolveContext ec)
10971 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10973 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10977 public override void ResolveBase (ResolveContext ec)
10979 base.ResolveBase (ec);
10980 type = ec.CurrentType.BaseType;
10983 public override object Accept (StructuralVisitor visitor)
10985 return visitor.Visit (this);
10990 /// This class exists solely to pass the Type around and to be a dummy
10991 /// that can be passed to the conversion functions (this is used by
10992 /// foreach implementation to typecast the object return value from
10993 /// get_Current into the proper type. All code has been generated and
10994 /// we only care about the side effect conversions to be performed
10996 /// This is also now used as a placeholder where a no-action expression
10997 /// is needed (the `New' class).
10999 public class EmptyExpression : Expression
11001 sealed class OutAccessExpression : EmptyExpression
11003 public OutAccessExpression (TypeSpec t)
11008 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11010 rc.Report.Error (206, right_side.Location,
11011 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11017 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11018 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11019 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11020 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11021 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11022 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11023 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11024 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11026 public EmptyExpression (TypeSpec t)
11029 eclass = ExprClass.Value;
11030 loc = Location.Null;
11033 protected override void CloneTo (CloneContext clonectx, Expression target)
11037 public override bool ContainsEmitWithAwait ()
11042 public override Expression CreateExpressionTree (ResolveContext ec)
11044 throw new NotSupportedException ("ET");
11047 protected override Expression DoResolve (ResolveContext ec)
11052 public override void Emit (EmitContext ec)
11054 // nothing, as we only exist to not do anything.
11057 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11061 public override void EmitSideEffect (EmitContext ec)
11065 public override object Accept (StructuralVisitor visitor)
11067 return visitor.Visit (this);
11071 sealed class EmptyAwaitExpression : EmptyExpression
11073 public EmptyAwaitExpression (TypeSpec type)
11078 public override bool ContainsEmitWithAwait ()
11085 // Empty statement expression
11087 public sealed class EmptyExpressionStatement : ExpressionStatement
11089 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11091 private EmptyExpressionStatement ()
11093 loc = Location.Null;
11096 public override bool ContainsEmitWithAwait ()
11101 public override Expression CreateExpressionTree (ResolveContext ec)
11106 public override void EmitStatement (EmitContext ec)
11111 protected override Expression DoResolve (ResolveContext ec)
11113 eclass = ExprClass.Value;
11114 type = ec.BuiltinTypes.Object;
11118 public override void Emit (EmitContext ec)
11123 public override object Accept (StructuralVisitor visitor)
11125 return visitor.Visit (this);
11129 public class ErrorExpression : EmptyExpression
11131 public static readonly ErrorExpression Instance = new ErrorExpression ();
11133 private ErrorExpression ()
11134 : base (InternalType.ErrorType)
11138 public override Expression CreateExpressionTree (ResolveContext ec)
11143 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11148 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11152 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11156 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11160 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11164 public override object Accept (StructuralVisitor visitor)
11166 return visitor.Visit (this);
11170 public class UserCast : Expression {
11174 public UserCast (MethodSpec method, Expression source, Location l)
11176 if (source == null)
11177 throw new ArgumentNullException ("source");
11179 this.method = method;
11180 this.source = source;
11181 type = method.ReturnType;
11185 public Expression Source {
11194 public override bool ContainsEmitWithAwait ()
11196 return source.ContainsEmitWithAwait ();
11199 public override Expression CreateExpressionTree (ResolveContext ec)
11201 Arguments args = new Arguments (3);
11202 args.Add (new Argument (source.CreateExpressionTree (ec)));
11203 args.Add (new Argument (new TypeOf (type, loc)));
11204 args.Add (new Argument (new TypeOfMethod (method, loc)));
11205 return CreateExpressionFactoryCall (ec, "Convert", args);
11208 protected override Expression DoResolve (ResolveContext ec)
11210 method.CheckObsoleteness (ec, source.Location);
11212 eclass = ExprClass.Value;
11216 public override void Emit (EmitContext ec)
11219 ec.MarkCallEntry (loc);
11220 ec.Emit (OpCodes.Call, method);
11223 public override void FlowAnalysis (FlowAnalysisContext fc)
11225 source.FlowAnalysis (fc);
11228 public override string GetSignatureForError ()
11230 return TypeManager.CSharpSignature (method);
11233 public override SLE.Expression MakeExpression (BuilderContext ctx)
11236 return base.MakeExpression (ctx);
11238 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11244 // Holds additional type specifiers like ?, *, []
11246 public class ComposedTypeSpecifier
11248 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11250 public readonly int Dimension;
11251 public readonly Location Location;
11253 public ComposedTypeSpecifier (int specifier, Location loc)
11255 this.Dimension = specifier;
11256 this.Location = loc;
11260 public bool IsNullable {
11262 return Dimension == -1;
11266 public bool IsPointer {
11268 return Dimension == -2;
11272 public ComposedTypeSpecifier Next { get; set; }
11276 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11278 return new ComposedTypeSpecifier (dimension, loc);
11281 public static ComposedTypeSpecifier CreateNullable (Location loc)
11283 return new ComposedTypeSpecifier (-1, loc);
11286 public static ComposedTypeSpecifier CreatePointer (Location loc)
11288 return new ComposedTypeSpecifier (-2, loc);
11291 public string GetSignatureForError ()
11296 ArrayContainer.GetPostfixSignature (Dimension);
11298 return Next != null ? s + Next.GetSignatureForError () : s;
11303 // This class is used to "construct" the type during a typecast
11304 // operation. Since the Type.GetType class in .NET can parse
11305 // the type specification, we just use this to construct the type
11306 // one bit at a time.
11308 public class ComposedCast : TypeExpr {
11309 FullNamedExpression left;
11310 ComposedTypeSpecifier spec;
11312 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11315 throw new ArgumentNullException ("spec");
11319 this.loc = left.Location;
11322 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11324 type = left.ResolveAsType (ec);
11328 eclass = ExprClass.Type;
11330 var single_spec = spec;
11332 if (single_spec.IsNullable) {
11333 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11337 single_spec = single_spec.Next;
11338 } else if (single_spec.IsPointer) {
11340 // Declared fields cannot have unmanaged check done before all types are defined
11342 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11345 if (!ec.IsUnsafe) {
11346 UnsafeError (ec.Module.Compiler.Report, loc);
11350 type = PointerContainer.MakeType (ec.Module, type);
11351 single_spec = single_spec.Next;
11352 } while (single_spec != null && single_spec.IsPointer);
11355 if (single_spec != null && single_spec.Dimension > 0) {
11356 if (type.IsSpecialRuntimeType) {
11357 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11358 } else if (type.IsStatic) {
11359 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11360 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11361 type.GetSignatureForError ());
11363 MakeArray (ec.Module, single_spec);
11370 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11372 if (spec.Next != null)
11373 MakeArray (module, spec.Next);
11375 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11378 public override string GetSignatureForError ()
11380 return left.GetSignatureForError () + spec.GetSignatureForError ();
11383 public override object Accept (StructuralVisitor visitor)
11385 return visitor.Visit (this);
11389 class FixedBufferPtr : Expression
11391 readonly Expression array;
11393 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11395 this.type = array_type;
11396 this.array = array;
11400 public override bool ContainsEmitWithAwait ()
11402 throw new NotImplementedException ();
11405 public override Expression CreateExpressionTree (ResolveContext ec)
11407 Error_PointerInsideExpressionTree (ec);
11411 public override void Emit(EmitContext ec)
11416 protected override Expression DoResolve (ResolveContext ec)
11418 type = PointerContainer.MakeType (ec.Module, type);
11419 eclass = ExprClass.Value;
11426 // This class is used to represent the address of an array, used
11427 // only by the Fixed statement, this generates "&a [0]" construct
11428 // for fixed (char *pa = a)
11430 class ArrayPtr : FixedBufferPtr
11432 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11433 base (array, array_type, l)
11437 public override void Emit (EmitContext ec)
11442 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11447 // Encapsulates a conversion rules required for array indexes
11449 public class ArrayIndexCast : TypeCast
11451 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11452 : base (expr, returnType)
11454 if (expr.Type == returnType) // int -> int
11455 throw new ArgumentException ("unnecessary array index conversion");
11458 public override Expression CreateExpressionTree (ResolveContext ec)
11460 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11461 return base.CreateExpressionTree (ec);
11465 public override void Emit (EmitContext ec)
11469 switch (child.Type.BuiltinType) {
11470 case BuiltinTypeSpec.Type.UInt:
11471 ec.Emit (OpCodes.Conv_U);
11473 case BuiltinTypeSpec.Type.Long:
11474 ec.Emit (OpCodes.Conv_Ovf_I);
11476 case BuiltinTypeSpec.Type.ULong:
11477 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11480 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11486 // Implements the `stackalloc' keyword
11488 public class StackAlloc : Expression {
11493 public StackAlloc (Expression type, Expression count, Location l)
11496 this.count = count;
11500 public Expression TypeExpression {
11506 public Expression CountExpression {
11512 public override bool ContainsEmitWithAwait ()
11517 public override Expression CreateExpressionTree (ResolveContext ec)
11519 throw new NotSupportedException ("ET");
11522 protected override Expression DoResolve (ResolveContext ec)
11524 count = count.Resolve (ec);
11528 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11529 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11534 Constant c = count as Constant;
11535 if (c != null && c.IsNegative) {
11536 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11539 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11540 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11543 otype = texpr.ResolveAsType (ec);
11547 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11550 type = PointerContainer.MakeType (ec.Module, otype);
11551 eclass = ExprClass.Value;
11556 public override void Emit (EmitContext ec)
11558 int size = BuiltinTypeSpec.GetSize (otype);
11563 ec.Emit (OpCodes.Sizeof, otype);
11567 ec.Emit (OpCodes.Mul_Ovf_Un);
11568 ec.Emit (OpCodes.Localloc);
11571 protected override void CloneTo (CloneContext clonectx, Expression t)
11573 StackAlloc target = (StackAlloc) t;
11574 target.count = count.Clone (clonectx);
11575 target.texpr = texpr.Clone (clonectx);
11578 public override object Accept (StructuralVisitor visitor)
11580 return visitor.Visit (this);
11585 // An object initializer expression
11587 public class ElementInitializer : Assign
11589 public readonly string Name;
11591 public ElementInitializer (string name, Expression initializer, Location loc)
11592 : base (null, initializer, loc)
11597 public bool IsDictionaryInitializer {
11599 return Name == null;
11603 protected override void CloneTo (CloneContext clonectx, Expression t)
11605 ElementInitializer target = (ElementInitializer) t;
11606 target.source = source.Clone (clonectx);
11609 public override Expression CreateExpressionTree (ResolveContext ec)
11611 Arguments args = new Arguments (2);
11612 FieldExpr fe = target as FieldExpr;
11614 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11616 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11619 Expression arg_expr;
11620 var cinit = source as CollectionOrObjectInitializers;
11621 if (cinit == null) {
11623 arg_expr = source.CreateExpressionTree (ec);
11625 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11626 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11629 args.Add (new Argument (arg_expr));
11630 return CreateExpressionFactoryCall (ec, mname, args);
11633 protected override Expression DoResolve (ResolveContext ec)
11635 if (source == null)
11636 return EmptyExpressionStatement.Instance;
11638 if (!ResolveElement (ec))
11641 if (source is CollectionOrObjectInitializers) {
11642 target = target.Resolve (ec);
11643 if (target == null)
11646 Expression previous = ec.CurrentInitializerVariable;
11647 ec.CurrentInitializerVariable = target;
11648 source = source.Resolve (ec);
11649 ec.CurrentInitializerVariable = previous;
11650 if (source == null)
11653 eclass = source.eclass;
11654 type = source.Type;
11659 return base.DoResolve (ec);
11662 public override void EmitStatement (EmitContext ec)
11664 if (source is CollectionOrObjectInitializers)
11667 base.EmitStatement (ec);
11670 protected virtual bool ResolveElement (ResolveContext rc)
11672 var t = rc.CurrentInitializerVariable.Type;
11673 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11674 Arguments args = new Arguments (1);
11675 args.Add (new Argument (rc.CurrentInitializerVariable));
11676 target = new DynamicMemberBinder (Name, args, loc);
11678 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11679 if (member == null) {
11680 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11682 if (member != null) {
11683 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11684 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11689 if (member == null) {
11690 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11694 var me = member as MemberExpr;
11695 if (me is EventExpr) {
11696 me = me.ResolveMemberAccess (rc, null, null);
11697 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11698 rc.Report.Error (1913, loc,
11699 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11700 member.GetSignatureForError ());
11706 rc.Report.Error (1914, loc,
11707 "Static field or property `{0}' cannot be assigned in an object initializer",
11708 me.GetSignatureForError ());
11712 me.InstanceExpression = rc.CurrentInitializerVariable;
11720 // A collection initializer expression
11722 class CollectionElementInitializer : Invocation
11724 public class ElementInitializerArgument : Argument
11726 public ElementInitializerArgument (Expression e)
11732 sealed class AddMemberAccess : MemberAccess
11734 public AddMemberAccess (Expression expr, Location loc)
11735 : base (expr, "Add", loc)
11739 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11741 if (TypeManager.HasElementType (type))
11744 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11748 public CollectionElementInitializer (Expression argument)
11749 : base (null, new Arguments (1))
11751 base.arguments.Add (new ElementInitializerArgument (argument));
11752 this.loc = argument.Location;
11755 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11756 : base (null, new Arguments (arguments.Count))
11758 foreach (Expression e in arguments)
11759 base.arguments.Add (new ElementInitializerArgument (e));
11764 public CollectionElementInitializer (Location loc)
11765 : base (null, null)
11770 public override Expression CreateExpressionTree (ResolveContext ec)
11772 Arguments args = new Arguments (2);
11773 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11775 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11776 foreach (Argument a in arguments) {
11777 if (a.ArgType == Argument.AType.ExtensionType) {
11778 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11781 expr_initializers.Add (a.CreateExpressionTree (ec));
11784 args.Add (new Argument (new ArrayCreation (
11785 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11786 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11789 protected override void CloneTo (CloneContext clonectx, Expression t)
11791 CollectionElementInitializer target = (CollectionElementInitializer) t;
11792 if (arguments != null)
11793 target.arguments = arguments.Clone (clonectx);
11796 protected override Expression DoResolve (ResolveContext ec)
11798 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11800 return base.DoResolve (ec);
11804 class DictionaryElementInitializer : ElementInitializer
11806 readonly Arguments args;
11808 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11809 : base (null, initializer, loc)
11811 this.args = arguments;
11814 public override Expression CreateExpressionTree (ResolveContext ec)
11816 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11820 protected override bool ResolveElement (ResolveContext rc)
11822 var init = rc.CurrentInitializerVariable;
11823 var type = init.Type;
11825 if (type.IsArray) {
11826 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11830 if (type.IsPointer) {
11831 target = init.MakePointerAccess (rc, type, args);
11835 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11836 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11837 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11841 target = new IndexerExpr (indexers, type, init, args, loc);
11847 // A block of object or collection initializers
11849 public class CollectionOrObjectInitializers : ExpressionStatement
11851 IList<Expression> initializers;
11852 bool is_collection_initialization;
11854 public CollectionOrObjectInitializers (Location loc)
11855 : this (new Expression[0], loc)
11859 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11861 this.initializers = initializers;
11865 public IList<Expression> Initializers {
11867 return initializers;
11871 public bool IsEmpty {
11873 return initializers.Count == 0;
11877 public bool IsCollectionInitializer {
11879 return is_collection_initialization;
11883 protected override void CloneTo (CloneContext clonectx, Expression target)
11885 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11887 t.initializers = new List<Expression> (initializers.Count);
11888 foreach (var e in initializers)
11889 t.initializers.Add (e.Clone (clonectx));
11892 public override bool ContainsEmitWithAwait ()
11894 foreach (var e in initializers) {
11895 if (e.ContainsEmitWithAwait ())
11902 public override Expression CreateExpressionTree (ResolveContext ec)
11904 return CreateExpressionTree (ec, false);
11907 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11909 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11910 foreach (Expression e in initializers) {
11911 Expression expr = e.CreateExpressionTree (ec);
11913 expr_initializers.Add (expr);
11917 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11919 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11922 protected override Expression DoResolve (ResolveContext ec)
11924 List<string> element_names = null;
11925 for (int i = 0; i < initializers.Count; ++i) {
11926 Expression initializer = initializers [i];
11927 ElementInitializer element_initializer = initializer as ElementInitializer;
11930 if (element_initializer != null) {
11931 element_names = new List<string> (initializers.Count);
11932 if (!element_initializer.IsDictionaryInitializer)
11933 element_names.Add (element_initializer.Name);
11934 } else if (initializer is CompletingExpression) {
11935 initializer.Resolve (ec);
11936 throw new InternalErrorException ("This line should never be reached");
11938 var t = ec.CurrentInitializerVariable.Type;
11939 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11940 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11941 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11942 "object initializer because type `{1}' does not implement `{2}' interface",
11943 ec.CurrentInitializerVariable.GetSignatureForError (),
11944 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11945 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11948 is_collection_initialization = true;
11951 if (is_collection_initialization != (element_initializer == null)) {
11952 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11953 is_collection_initialization ? "collection initializer" : "object initializer");
11957 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11958 if (element_names.Contains (element_initializer.Name)) {
11959 ec.Report.Error (1912, element_initializer.Location,
11960 "An object initializer includes more than one member `{0}' initialization",
11961 element_initializer.Name);
11963 element_names.Add (element_initializer.Name);
11968 Expression e = initializer.Resolve (ec);
11969 if (e == EmptyExpressionStatement.Instance)
11970 initializers.RemoveAt (i--);
11972 initializers [i] = e;
11975 type = ec.CurrentInitializerVariable.Type;
11976 if (is_collection_initialization) {
11977 if (TypeManager.HasElementType (type)) {
11978 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11979 type.GetSignatureForError ());
11983 eclass = ExprClass.Variable;
11987 public override void Emit (EmitContext ec)
11989 EmitStatement (ec);
11992 public override void EmitStatement (EmitContext ec)
11994 foreach (ExpressionStatement e in initializers) {
11995 // TODO: need location region
11996 ec.Mark (e.Location);
11997 e.EmitStatement (ec);
12001 public override void FlowAnalysis (FlowAnalysisContext fc)
12003 foreach (var initializer in initializers) {
12004 if (initializer != null)
12005 initializer.FlowAnalysis (fc);
12011 // New expression with element/object initializers
12013 public class NewInitialize : New
12016 // This class serves as a proxy for variable initializer target instances.
12017 // A real variable is assigned later when we resolve left side of an
12020 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12022 NewInitialize new_instance;
12024 public InitializerTargetExpression (NewInitialize newInstance)
12026 this.type = newInstance.type;
12027 this.loc = newInstance.loc;
12028 this.eclass = newInstance.eclass;
12029 this.new_instance = newInstance;
12032 public override bool ContainsEmitWithAwait ()
12037 public override Expression CreateExpressionTree (ResolveContext ec)
12039 // Should not be reached
12040 throw new NotSupportedException ("ET");
12043 protected override Expression DoResolve (ResolveContext ec)
12048 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12053 public override void Emit (EmitContext ec)
12055 Expression e = (Expression) new_instance.instance;
12059 public override Expression EmitToField (EmitContext ec)
12061 return (Expression) new_instance.instance;
12064 #region IMemoryLocation Members
12066 public void AddressOf (EmitContext ec, AddressOp mode)
12068 new_instance.instance.AddressOf (ec, mode);
12074 CollectionOrObjectInitializers initializers;
12075 IMemoryLocation instance;
12076 DynamicExpressionStatement dynamic;
12078 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12079 : base (requested_type, arguments, l)
12081 this.initializers = initializers;
12084 public CollectionOrObjectInitializers Initializers {
12086 return initializers;
12090 protected override void CloneTo (CloneContext clonectx, Expression t)
12092 base.CloneTo (clonectx, t);
12094 NewInitialize target = (NewInitialize) t;
12095 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12098 public override bool ContainsEmitWithAwait ()
12100 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12103 public override Expression CreateExpressionTree (ResolveContext ec)
12105 Arguments args = new Arguments (2);
12106 args.Add (new Argument (base.CreateExpressionTree (ec)));
12107 if (!initializers.IsEmpty)
12108 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12110 return CreateExpressionFactoryCall (ec,
12111 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12115 protected override Expression DoResolve (ResolveContext ec)
12117 Expression e = base.DoResolve (ec);
12121 if (type.IsDelegate) {
12122 ec.Report.Error (1958, Initializers.Location,
12123 "Object and collection initializers cannot be used to instantiate a delegate");
12126 Expression previous = ec.CurrentInitializerVariable;
12127 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12128 initializers.Resolve (ec);
12129 ec.CurrentInitializerVariable = previous;
12131 dynamic = e as DynamicExpressionStatement;
12132 if (dynamic != null)
12138 public override void Emit (EmitContext ec)
12140 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12141 var fe = ec.GetTemporaryField (type);
12143 if (!Emit (ec, fe))
12152 public override bool Emit (EmitContext ec, IMemoryLocation target)
12155 // Expression is initialized into temporary target then moved
12156 // to real one for atomicity
12158 IMemoryLocation temp_target = target;
12160 LocalTemporary temp = null;
12161 bool by_ref = false;
12162 if (!initializers.IsEmpty) {
12163 temp_target = target as LocalTemporary;
12164 if (temp_target == null)
12165 temp_target = target as StackFieldExpr;
12167 if (temp_target == null) {
12168 var vr = target as VariableReference;
12169 if (vr != null && vr.IsRef) {
12175 if (temp_target == null)
12176 temp_target = temp = new LocalTemporary (type);
12179 bool left_on_stack;
12180 if (dynamic != null) {
12182 left_on_stack = true;
12184 left_on_stack = base.Emit (ec, temp_target);
12187 if (initializers.IsEmpty)
12188 return left_on_stack;
12190 StackFieldExpr sf = null;
12192 // Move a new instance (reference-type) to local temporary variable
12193 if (left_on_stack) {
12195 temp_target = temp = new LocalTemporary (type);
12201 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12203 throw new NotImplementedException ();
12205 sf = ec.GetTemporaryField (type);
12206 sf.EmitAssign (ec, temp, false, false);
12209 left_on_stack = false;
12213 instance = temp_target;
12215 initializers.Emit (ec);
12217 ((Expression)temp_target).Emit (ec);
12223 sf.IsAvailableForReuse = true;
12228 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12230 instance = base.EmitAddressOf (ec, Mode);
12232 if (!initializers.IsEmpty)
12233 initializers.Emit (ec);
12238 public override void FlowAnalysis (FlowAnalysisContext fc)
12240 base.FlowAnalysis (fc);
12241 initializers.FlowAnalysis (fc);
12244 public override object Accept (StructuralVisitor visitor)
12246 return visitor.Visit (this);
12250 public class NewAnonymousType : New
12252 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12254 List<AnonymousTypeParameter> parameters;
12255 readonly TypeContainer parent;
12256 AnonymousTypeClass anonymous_type;
12258 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12259 : base (null, null, loc)
12261 this.parameters = parameters;
12262 this.parent = parent;
12265 public List<AnonymousTypeParameter> Parameters {
12267 return this.parameters;
12271 protected override void CloneTo (CloneContext clonectx, Expression target)
12273 if (parameters == null)
12276 NewAnonymousType t = (NewAnonymousType) target;
12277 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12278 foreach (AnonymousTypeParameter atp in parameters)
12279 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12282 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12284 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12288 type = AnonymousTypeClass.Create (parent, parameters, loc);
12292 int errors = ec.Report.Errors;
12293 type.CreateContainer ();
12294 type.DefineContainer ();
12296 if ((ec.Report.Errors - errors) == 0) {
12297 parent.Module.AddAnonymousType (type);
12298 type.PrepareEmit ();
12304 public override Expression CreateExpressionTree (ResolveContext ec)
12306 if (parameters == null)
12307 return base.CreateExpressionTree (ec);
12309 var init = new ArrayInitializer (parameters.Count, loc);
12310 foreach (var m in anonymous_type.Members) {
12311 var p = m as Property;
12313 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12316 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12317 foreach (Argument a in arguments)
12318 ctor_args.Add (a.CreateExpressionTree (ec));
12320 Arguments args = new Arguments (3);
12321 args.Add (new Argument (new TypeOfMethod (method, loc)));
12322 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12323 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12325 return CreateExpressionFactoryCall (ec, "New", args);
12328 protected override Expression DoResolve (ResolveContext ec)
12330 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12331 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12335 if (parameters == null) {
12336 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12337 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12338 return base.DoResolve (ec);
12341 bool error = false;
12342 arguments = new Arguments (parameters.Count);
12343 var t_args = new TypeSpec [parameters.Count];
12344 for (int i = 0; i < parameters.Count; ++i) {
12345 Expression e = parameters [i].Resolve (ec);
12351 arguments.Add (new Argument (e));
12352 t_args [i] = e.Type;
12358 anonymous_type = CreateAnonymousType (ec, parameters);
12359 if (anonymous_type == null)
12362 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12363 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12364 eclass = ExprClass.Value;
12368 public override object Accept (StructuralVisitor visitor)
12370 return visitor.Visit (this);
12374 public class AnonymousTypeParameter : ShimExpression
12376 public readonly string Name;
12378 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12379 : base (initializer)
12385 public AnonymousTypeParameter (Parameter parameter)
12386 : base (new SimpleName (parameter.Name, parameter.Location))
12388 this.Name = parameter.Name;
12389 this.loc = parameter.Location;
12392 public override bool Equals (object o)
12394 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12395 return other != null && Name == other.Name;
12398 public override int GetHashCode ()
12400 return Name.GetHashCode ();
12403 protected override Expression DoResolve (ResolveContext ec)
12405 Expression e = expr.Resolve (ec);
12409 if (e.eclass == ExprClass.MethodGroup) {
12410 Error_InvalidInitializer (ec, e.ExprClassName);
12415 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12416 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12423 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12425 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12426 Name, initializer);
12430 public class CatchFilterExpression : BooleanExpression
12432 public CatchFilterExpression (Expression expr, Location loc)
12439 public class InterpolatedString : Expression
12441 readonly StringLiteral start, end;
12442 List<Expression> interpolations;
12443 Arguments arguments;
12445 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12447 this.start = start;
12449 this.interpolations = interpolations;
12450 loc = start.Location;
12453 protected override void CloneTo (CloneContext clonectx, Expression t)
12455 InterpolatedString target = (InterpolatedString) t;
12457 if (interpolations != null) {
12458 target.interpolations = new List<Expression> ();
12459 foreach (var interpolation in interpolations) {
12460 target.interpolations.Add (interpolation.Clone (clonectx));
12465 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12467 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12468 if (factory == null)
12471 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12472 var res = new Invocation (ma, arguments).Resolve (rc);
12473 if (res != null && res.Type != type)
12474 res = Convert.ExplicitConversion (rc, res, type, loc);
12479 public override bool ContainsEmitWithAwait ()
12481 if (interpolations == null)
12484 foreach (var expr in interpolations) {
12485 if (expr.ContainsEmitWithAwait ())
12492 public override Expression CreateExpressionTree (ResolveContext rc)
12494 var best = ResolveBestFormatOverload (rc);
12498 Expression instance = new NullLiteral (loc);
12499 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12500 return CreateExpressionFactoryCall (rc, "Call", args);
12503 protected override Expression DoResolve (ResolveContext rc)
12507 if (interpolations == null) {
12509 arguments = new Arguments (1);
12511 arguments = new Arguments (interpolations.Count);
12513 var sb = new StringBuilder (start.Value);
12514 for (int i = 0; i < interpolations.Count; ++i) {
12516 sb.Append ('{').Append (i / 2);
12517 var isi = (InterpolatedStringInsert)interpolations [i];
12518 if (isi.Alignment != null) {
12520 var value = isi.ResolveAligment (rc);
12522 sb.Append (value.Value);
12525 if (isi.Format != null) {
12527 sb.Append (isi.Format);
12531 arguments.Add (new Argument (isi.Resolve (rc)));
12533 sb.Append (((StringLiteral)interpolations [i]).Value);
12537 sb.Append (end.Value);
12538 str = sb.ToString ();
12541 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12543 eclass = ExprClass.Value;
12544 type = rc.BuiltinTypes.String;
12548 public override void Emit (EmitContext ec)
12550 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12551 if (interpolations == null) {
12552 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12553 if (str != start.Value)
12554 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12561 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12565 var ca = new CallEmitter ();
12566 ca.Emit (ec, best, arguments, loc);
12569 public override void FlowAnalysis (FlowAnalysisContext fc)
12571 if (interpolations != null) {
12572 foreach (var expr in interpolations) {
12573 expr.FlowAnalysis (fc);
12578 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12580 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12581 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12582 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12586 public class InterpolatedStringInsert : CompositeExpression
12588 public InterpolatedStringInsert (Expression expr)
12593 public Expression Alignment { get; set; }
12594 public string Format { get; set; }
12596 protected override void CloneTo (CloneContext clonectx, Expression t)
12598 var target = (InterpolatedStringInsert)t;
12599 target.expr = expr.Clone (clonectx);
12600 if (Alignment != null)
12601 target.Alignment = Alignment.Clone (clonectx);
12604 protected override Expression DoResolve (ResolveContext rc)
12606 var expr = base.DoResolve (rc);
12611 // For better error reporting, assumes the built-in implementation uses object
12614 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12617 public override void FlowAnalysis (FlowAnalysisContext fc)
12619 Child.FlowAnalysis (fc);
12622 public int? ResolveAligment (ResolveContext rc)
12624 var c = Alignment.ResolveLabelConstant (rc);
12628 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12632 var value = (int) c.GetValueAsLong ();
12633 if (value > 32767 || value < -32767) {
12634 rc.Report.Warning (8094, 1, Alignment.Location,
12635 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");