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;
114 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
115 res = expr.Resolve (rc);
118 var constant = res as Constant;
119 if (constant != null && constant.IsLiteral) {
120 if (res is NullLiteral)
123 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
129 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
131 return expr.DoResolveLValue (ec, right_side);
134 public override object Accept (StructuralVisitor visitor)
136 return visitor.Visit (this);
139 public override bool HasConditionalAccess ()
146 // Unary implements unary expressions.
148 public class Unary : Expression
150 public enum Operator : byte {
151 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
155 public readonly Operator Oper;
156 public Expression Expr;
157 ConvCast.Mode enum_conversion;
159 public Unary (Operator op, Expression expr, Location loc)
167 // This routine will attempt to simplify the unary expression when the
168 // argument is a constant.
170 Constant TryReduceConstant (ResolveContext ec, Constant constant)
174 while (e is EmptyConstantCast)
175 e = ((EmptyConstantCast) e).child;
177 if (e is SideEffectConstant) {
178 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
179 return r == null ? null : new SideEffectConstant (r, e, r.Location);
182 TypeSpec expr_type = e.Type;
185 case Operator.UnaryPlus:
186 // Unary numeric promotions
187 switch (expr_type.BuiltinType) {
188 case BuiltinTypeSpec.Type.Byte:
189 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
190 case BuiltinTypeSpec.Type.SByte:
191 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
192 case BuiltinTypeSpec.Type.Short:
193 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
194 case BuiltinTypeSpec.Type.UShort:
195 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
196 case BuiltinTypeSpec.Type.Char:
197 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
199 // Predefined operators
200 case BuiltinTypeSpec.Type.Int:
201 case BuiltinTypeSpec.Type.UInt:
202 case BuiltinTypeSpec.Type.Long:
203 case BuiltinTypeSpec.Type.ULong:
204 case BuiltinTypeSpec.Type.Float:
205 case BuiltinTypeSpec.Type.Double:
206 case BuiltinTypeSpec.Type.Decimal:
212 case Operator.UnaryNegation:
213 // Unary numeric promotions
214 switch (expr_type.BuiltinType) {
215 case BuiltinTypeSpec.Type.Byte:
216 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
217 case BuiltinTypeSpec.Type.SByte:
218 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
219 case BuiltinTypeSpec.Type.Short:
220 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
221 case BuiltinTypeSpec.Type.UShort:
222 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
223 case BuiltinTypeSpec.Type.Char:
224 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
226 // Predefined operators
227 case BuiltinTypeSpec.Type.Int:
228 int ivalue = ((IntConstant) e).Value;
229 if (ivalue == int.MinValue) {
230 if (ec.ConstantCheckState) {
231 ConstantFold.Error_CompileTimeOverflow (ec, loc);
236 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
238 case BuiltinTypeSpec.Type.Long:
239 long lvalue = ((LongConstant) e).Value;
240 if (lvalue == long.MinValue) {
241 if (ec.ConstantCheckState) {
242 ConstantFold.Error_CompileTimeOverflow (ec, loc);
247 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
249 case BuiltinTypeSpec.Type.UInt:
250 UIntLiteral uil = constant as UIntLiteral;
252 if (uil.Value == int.MaxValue + (uint) 1)
253 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
254 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
256 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
259 case BuiltinTypeSpec.Type.ULong:
260 ULongLiteral ull = constant as ULongLiteral;
261 if (ull != null && ull.Value == 9223372036854775808)
262 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
265 case BuiltinTypeSpec.Type.Float:
266 FloatLiteral fl = constant as FloatLiteral;
267 // For better error reporting
269 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
271 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
273 case BuiltinTypeSpec.Type.Double:
274 DoubleLiteral dl = constant as DoubleLiteral;
275 // For better error reporting
277 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
279 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
281 case BuiltinTypeSpec.Type.Decimal:
282 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
287 case Operator.LogicalNot:
288 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
291 bool b = (bool)e.GetValue ();
292 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
294 case Operator.OnesComplement:
295 // Unary numeric promotions
296 switch (expr_type.BuiltinType) {
297 case BuiltinTypeSpec.Type.Byte:
298 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
299 case BuiltinTypeSpec.Type.SByte:
300 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
301 case BuiltinTypeSpec.Type.Short:
302 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
303 case BuiltinTypeSpec.Type.UShort:
304 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
305 case BuiltinTypeSpec.Type.Char:
306 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
308 // Predefined operators
309 case BuiltinTypeSpec.Type.Int:
310 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
311 case BuiltinTypeSpec.Type.UInt:
312 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
313 case BuiltinTypeSpec.Type.Long:
314 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
315 case BuiltinTypeSpec.Type.ULong:
316 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
318 if (e is EnumConstant) {
319 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
322 // Numeric promotion upgraded types to int but for enum constant
323 // original underlying constant type is needed
325 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
326 int v = ((IntConstant) res).Value;
327 switch (((EnumConstant) e).Child.Type.BuiltinType) {
328 case BuiltinTypeSpec.Type.UShort:
329 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
331 case BuiltinTypeSpec.Type.Short:
332 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
334 case BuiltinTypeSpec.Type.Byte:
335 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
337 case BuiltinTypeSpec.Type.SByte:
338 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
343 res = new EnumConstant (res, expr_type);
349 throw new Exception ("Can not constant fold: " + Oper.ToString());
352 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
354 eclass = ExprClass.Value;
356 TypeSpec expr_type = expr.Type;
357 Expression best_expr;
359 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
362 // Primitive types first
364 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
365 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
366 if (best_expr == null)
369 type = best_expr.Type;
375 // E operator ~(E x);
377 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
378 return ResolveEnumOperator (ec, expr, predefined);
380 return ResolveUserType (ec, expr, predefined);
383 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
385 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
386 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
387 if (best_expr == null)
391 enum_conversion = Binary.GetEnumResultCast (underlying_type);
393 return EmptyCast.Create (this, type);
396 public override bool ContainsEmitWithAwait ()
398 return Expr.ContainsEmitWithAwait ();
401 public override Expression CreateExpressionTree (ResolveContext ec)
403 return CreateExpressionTree (ec, null);
406 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
410 case Operator.AddressOf:
411 Error_PointerInsideExpressionTree (ec);
413 case Operator.UnaryNegation:
414 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
415 method_name = "NegateChecked";
417 method_name = "Negate";
419 case Operator.OnesComplement:
420 case Operator.LogicalNot:
423 case Operator.UnaryPlus:
424 method_name = "UnaryPlus";
427 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
430 Arguments args = new Arguments (2);
431 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
433 args.Add (new Argument (user_op));
435 return CreateExpressionFactoryCall (ec, method_name, args);
438 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
440 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
443 // 7.6.1 Unary plus operator
445 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
446 types.Int, types.UInt,
447 types.Long, types.ULong,
448 types.Float, types.Double,
453 // 7.6.2 Unary minus operator
455 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
456 types.Int, types.Long,
457 types.Float, types.Double,
462 // 7.6.3 Logical negation operator
464 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
469 // 7.6.4 Bitwise complement operator
471 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
472 types.Int, types.UInt,
473 types.Long, types.ULong
476 return predefined_operators;
480 // Unary numeric promotions
482 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
484 TypeSpec expr_type = expr.Type;
485 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
486 switch (expr_type.BuiltinType) {
487 case BuiltinTypeSpec.Type.Byte:
488 case BuiltinTypeSpec.Type.SByte:
489 case BuiltinTypeSpec.Type.Short:
490 case BuiltinTypeSpec.Type.UShort:
491 case BuiltinTypeSpec.Type.Char:
492 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
496 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
497 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
502 protected override Expression DoResolve (ResolveContext ec)
504 if (Oper == Operator.AddressOf) {
505 return ResolveAddressOf (ec);
508 Expr = Expr.Resolve (ec);
512 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
513 Arguments args = new Arguments (1);
514 args.Add (new Argument (Expr));
515 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
518 if (Expr.Type.IsNullableType)
519 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
522 // Attempt to use a constant folding operation.
524 Constant cexpr = Expr as Constant;
526 cexpr = TryReduceConstant (ec, cexpr);
531 Expression expr = ResolveOperator (ec, Expr);
533 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
536 // Reduce unary operator on predefined types
538 if (expr == this && Oper == Operator.UnaryPlus)
544 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
549 public override void Emit (EmitContext ec)
551 EmitOperator (ec, type);
554 protected void EmitOperator (EmitContext ec, TypeSpec type)
557 case Operator.UnaryPlus:
561 case Operator.UnaryNegation:
562 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
563 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
564 Expr = Expr.EmitToField (ec);
567 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
568 ec.Emit (OpCodes.Conv_U8);
570 ec.Emit (OpCodes.Sub_Ovf);
573 ec.Emit (OpCodes.Neg);
578 case Operator.LogicalNot:
581 ec.Emit (OpCodes.Ceq);
584 case Operator.OnesComplement:
586 ec.Emit (OpCodes.Not);
589 case Operator.AddressOf:
590 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
594 throw new Exception ("This should not happen: Operator = "
599 // Same trick as in Binary expression
601 if (enum_conversion != 0) {
602 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
603 ConvCast.Emit (ec, enum_conversion);
608 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
610 if (Oper == Operator.LogicalNot)
611 Expr.EmitBranchable (ec, target, !on_true);
613 base.EmitBranchable (ec, target, on_true);
616 public override void EmitSideEffect (EmitContext ec)
618 Expr.EmitSideEffect (ec);
621 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
623 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
624 oper, type.GetSignatureForError ());
627 public override void FlowAnalysis (FlowAnalysisContext fc)
629 FlowAnalysis (fc, false);
632 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
634 FlowAnalysis (fc, true);
637 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
639 if (Oper == Operator.AddressOf) {
640 var vr = Expr as VariableReference;
641 if (vr != null && vr.VariableInfo != null)
642 fc.SetVariableAssigned (vr.VariableInfo);
647 if (Oper == Operator.LogicalNot && conditional) {
648 Expr.FlowAnalysisConditional (fc);
650 var temp = fc.DefiniteAssignmentOnTrue;
651 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
652 fc.DefiniteAssignmentOnFalse = temp;
654 Expr.FlowAnalysis (fc);
659 // Converts operator to System.Linq.Expressions.ExpressionType enum name
661 string GetOperatorExpressionTypeName ()
664 case Operator.OnesComplement:
665 return "OnesComplement";
666 case Operator.LogicalNot:
668 case Operator.UnaryNegation:
670 case Operator.UnaryPlus:
673 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
677 static bool IsFloat (TypeSpec t)
679 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
683 // Returns a stringified representation of the Operator
685 public static string OperName (Operator oper)
688 case Operator.UnaryPlus:
690 case Operator.UnaryNegation:
692 case Operator.LogicalNot:
694 case Operator.OnesComplement:
696 case Operator.AddressOf:
700 throw new NotImplementedException (oper.ToString ());
703 public override SLE.Expression MakeExpression (BuilderContext ctx)
705 var expr = Expr.MakeExpression (ctx);
706 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
709 case Operator.UnaryNegation:
710 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
711 case Operator.LogicalNot:
712 return SLE.Expression.Not (expr);
713 case Operator.OnesComplement:
714 return SLE.Expression.OnesComplement (expr);
716 throw new NotImplementedException (Oper.ToString ());
720 Expression ResolveAddressOf (ResolveContext ec)
723 UnsafeError (ec, loc);
725 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
726 if (Expr == null || Expr.eclass != ExprClass.Variable) {
727 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
731 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
735 IVariableReference vr = Expr as IVariableReference;
738 is_fixed = vr.IsFixed;
739 vr.SetHasAddressTaken ();
742 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
745 IFixedExpression fe = Expr as IFixedExpression;
746 is_fixed = fe != null && fe.IsFixed;
749 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
750 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
753 type = PointerContainer.MakeType (ec.Module, Expr.Type);
754 eclass = ExprClass.Value;
758 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
760 expr = DoNumericPromotion (rc, Oper, expr);
761 TypeSpec expr_type = expr.Type;
762 foreach (TypeSpec t in predefined) {
770 // Perform user-operator overload resolution
772 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
774 CSharp.Operator.OpType op_type;
776 case Operator.LogicalNot:
777 op_type = CSharp.Operator.OpType.LogicalNot; break;
778 case Operator.OnesComplement:
779 op_type = CSharp.Operator.OpType.OnesComplement; break;
780 case Operator.UnaryNegation:
781 op_type = CSharp.Operator.OpType.UnaryNegation; break;
782 case Operator.UnaryPlus:
783 op_type = CSharp.Operator.OpType.UnaryPlus; break;
785 throw new InternalErrorException (Oper.ToString ());
788 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
792 Arguments args = new Arguments (1);
793 args.Add (new Argument (expr));
795 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
796 var oper = res.ResolveOperator (ec, ref args);
801 Expr = args [0].Expr;
802 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
806 // Unary user type overload resolution
808 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
810 Expression best_expr = ResolveUserOperator (ec, expr);
811 if (best_expr != null)
814 foreach (TypeSpec t in predefined) {
815 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
816 if (oper_expr == null)
819 if (oper_expr == ErrorExpression.Instance)
823 // decimal type is predefined but has user-operators
825 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
826 oper_expr = ResolveUserType (ec, oper_expr, predefined);
828 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
830 if (oper_expr == null)
833 if (best_expr == null) {
834 best_expr = oper_expr;
838 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
840 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
841 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
843 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
850 best_expr = oper_expr;
853 if (best_expr == null)
857 // HACK: Decimal user-operator is included in standard operators
859 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
863 type = best_expr.Type;
867 protected override void CloneTo (CloneContext clonectx, Expression t)
869 Unary target = (Unary) t;
871 target.Expr = Expr.Clone (clonectx);
874 public override object Accept (StructuralVisitor visitor)
876 return visitor.Visit (this);
882 // Unary operators are turned into Indirection expressions
883 // after semantic analysis (this is so we can take the address
884 // of an indirection).
886 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
888 LocalTemporary temporary;
891 public Indirection (Expression expr, Location l)
897 public Expression Expr {
903 public bool IsFixed {
907 public override Location StartLocation {
909 return expr.StartLocation;
913 protected override void CloneTo (CloneContext clonectx, Expression t)
915 Indirection target = (Indirection) t;
916 target.expr = expr.Clone (clonectx);
919 public override bool ContainsEmitWithAwait ()
921 throw new NotImplementedException ();
924 public override Expression CreateExpressionTree (ResolveContext ec)
926 Error_PointerInsideExpressionTree (ec);
930 public override void Emit (EmitContext ec)
935 ec.EmitLoadFromPtr (Type);
938 public void Emit (EmitContext ec, bool leave_copy)
942 ec.Emit (OpCodes.Dup);
943 temporary = new LocalTemporary (expr.Type);
944 temporary.Store (ec);
948 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
950 prepared = isCompound;
955 ec.Emit (OpCodes.Dup);
959 ec.Emit (OpCodes.Dup);
960 temporary = new LocalTemporary (source.Type);
961 temporary.Store (ec);
964 ec.EmitStoreFromPtr (type);
966 if (temporary != null) {
968 temporary.Release (ec);
972 public void AddressOf (EmitContext ec, AddressOp Mode)
977 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
979 return DoResolve (ec);
982 protected override Expression DoResolve (ResolveContext ec)
984 expr = expr.Resolve (ec);
989 UnsafeError (ec, loc);
991 var pc = expr.Type as PointerContainer;
994 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1000 if (type.Kind == MemberKind.Void) {
1001 Error_VoidPointerOperation (ec);
1005 eclass = ExprClass.Variable;
1009 public override object Accept (StructuralVisitor visitor)
1011 return visitor.Visit (this);
1016 /// Unary Mutator expressions (pre and post ++ and --)
1020 /// UnaryMutator implements ++ and -- expressions. It derives from
1021 /// ExpressionStatement becuase the pre/post increment/decrement
1022 /// operators can be used in a statement context.
1024 /// FIXME: Idea, we could split this up in two classes, one simpler
1025 /// for the common case, and one with the extra fields for more complex
1026 /// classes (indexers require temporary access; overloaded require method)
1029 public class UnaryMutator : ExpressionStatement
1031 class DynamicPostMutator : Expression, IAssignMethod
1033 LocalTemporary temp;
1036 public DynamicPostMutator (Expression expr)
1039 this.type = expr.Type;
1040 this.loc = expr.Location;
1043 public override Expression CreateExpressionTree (ResolveContext ec)
1045 throw new NotImplementedException ("ET");
1048 protected override Expression DoResolve (ResolveContext rc)
1050 eclass = expr.eclass;
1054 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1056 expr.DoResolveLValue (ec, right_side);
1057 return DoResolve (ec);
1060 public override void Emit (EmitContext ec)
1065 public void Emit (EmitContext ec, bool leave_copy)
1067 throw new NotImplementedException ();
1071 // Emits target assignment using unmodified source value
1073 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1076 // Allocate temporary variable to keep original value before it's modified
1078 temp = new LocalTemporary (type);
1082 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1093 public enum Mode : byte {
1100 PreDecrement = IsDecrement,
1101 PostIncrement = IsPost,
1102 PostDecrement = IsPost | IsDecrement
1106 bool is_expr, recurse;
1108 protected Expression expr;
1110 // Holds the real operation
1111 Expression operation;
1113 public UnaryMutator (Mode m, Expression e, Location loc)
1120 public Mode UnaryMutatorMode {
1126 public Expression Expr {
1132 public override Location StartLocation {
1134 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1138 public override bool ContainsEmitWithAwait ()
1140 return expr.ContainsEmitWithAwait ();
1143 public override Expression CreateExpressionTree (ResolveContext ec)
1145 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1148 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1151 // Predefined ++ and -- operators exist for the following types:
1152 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1154 return new TypeSpec[] {
1170 protected override Expression DoResolve (ResolveContext ec)
1172 expr = expr.Resolve (ec);
1174 if (expr == null || expr.Type == InternalType.ErrorType)
1177 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1179 // Handle postfix unary operators using local
1180 // temporary variable
1182 if ((mode & Mode.IsPost) != 0)
1183 expr = new DynamicPostMutator (expr);
1185 Arguments args = new Arguments (1);
1186 args.Add (new Argument (expr));
1187 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1190 if (expr.Type.IsNullableType)
1191 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1193 return DoResolveOperation (ec);
1196 protected Expression DoResolveOperation (ResolveContext ec)
1198 eclass = ExprClass.Value;
1201 if (expr is RuntimeValueExpression) {
1204 // Use itself at the top of the stack
1205 operation = new EmptyExpression (type);
1209 // The operand of the prefix/postfix increment decrement operators
1210 // should be an expression that is classified as a variable,
1211 // a property access or an indexer access
1213 // TODO: Move to parser, expr is ATypeNameExpression
1214 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1215 expr = expr.ResolveLValue (ec, expr);
1217 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1221 // Step 1: Try to find a user operator, it has priority over predefined ones
1223 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1224 var methods = MemberCache.GetUserOperator (type, user_op, false);
1226 if (methods != null) {
1227 Arguments args = new Arguments (1);
1228 args.Add (new Argument (expr));
1230 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1231 var method = res.ResolveOperator (ec, ref args);
1235 args[0].Expr = operation;
1236 operation = new UserOperatorCall (method, args, null, loc);
1237 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1242 // Step 2: Try predefined types
1245 Expression source = null;
1246 bool primitive_type;
1249 // Predefined without user conversion first for speed-up
1251 // Predefined ++ and -- operators exist for the following types:
1252 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1254 switch (type.BuiltinType) {
1255 case BuiltinTypeSpec.Type.Byte:
1256 case BuiltinTypeSpec.Type.SByte:
1257 case BuiltinTypeSpec.Type.Short:
1258 case BuiltinTypeSpec.Type.UShort:
1259 case BuiltinTypeSpec.Type.Int:
1260 case BuiltinTypeSpec.Type.UInt:
1261 case BuiltinTypeSpec.Type.Long:
1262 case BuiltinTypeSpec.Type.ULong:
1263 case BuiltinTypeSpec.Type.Char:
1264 case BuiltinTypeSpec.Type.Float:
1265 case BuiltinTypeSpec.Type.Double:
1266 case BuiltinTypeSpec.Type.Decimal:
1268 primitive_type = true;
1271 primitive_type = false;
1273 // ++/-- on pointer variables of all types except void*
1274 if (type.IsPointer) {
1275 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1276 Error_VoidPointerOperation (ec);
1282 Expression best_source = null;
1283 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1284 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1286 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1290 if (best_source == null) {
1291 best_source = source;
1295 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1300 best_source = source;
1304 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1308 source = best_source;
1311 // ++/-- on enum types
1312 if (source == null && type.IsEnum)
1315 if (source == null) {
1316 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1323 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1324 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1325 operation = new Binary (op, source, one);
1326 operation = operation.Resolve (ec);
1327 if (operation == null)
1328 throw new NotImplementedException ("should not be reached");
1330 if (operation.Type != type) {
1332 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1334 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1340 void EmitCode (EmitContext ec, bool is_expr)
1343 this.is_expr = is_expr;
1344 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1347 public override void Emit (EmitContext ec)
1350 // We use recurse to allow ourselfs to be the source
1351 // of an assignment. This little hack prevents us from
1352 // having to allocate another expression
1355 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1363 EmitCode (ec, true);
1366 protected virtual void EmitOperation (EmitContext ec)
1368 operation.Emit (ec);
1371 public override void EmitStatement (EmitContext ec)
1373 EmitCode (ec, false);
1376 public override void FlowAnalysis (FlowAnalysisContext fc)
1378 expr.FlowAnalysis (fc);
1382 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1384 string GetOperatorExpressionTypeName ()
1386 return IsDecrement ? "Decrement" : "Increment";
1390 get { return (mode & Mode.IsDecrement) != 0; }
1394 public override SLE.Expression MakeExpression (BuilderContext ctx)
1396 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1397 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1398 return SLE.Expression.Assign (target, source);
1401 public static string OperName (Mode oper)
1403 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1406 protected override void CloneTo (CloneContext clonectx, Expression t)
1408 UnaryMutator target = (UnaryMutator) t;
1410 target.expr = expr.Clone (clonectx);
1413 public override object Accept (StructuralVisitor visitor)
1415 return visitor.Visit (this);
1421 // Base class for the `is' and `as' operators
1423 public abstract class Probe : Expression
1425 public Expression ProbeType;
1426 protected Expression expr;
1427 protected TypeSpec probe_type_expr;
1429 protected Probe (Expression expr, Expression probe_type, Location l)
1431 ProbeType = probe_type;
1436 public Expression Expr {
1442 public override bool ContainsEmitWithAwait ()
1444 return expr.ContainsEmitWithAwait ();
1447 protected Expression ResolveCommon (ResolveContext rc)
1449 expr = expr.Resolve (rc);
1453 ResolveProbeType (rc);
1454 if (probe_type_expr == null)
1457 if (probe_type_expr.IsStatic) {
1458 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1459 probe_type_expr.GetSignatureForError ());
1463 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1464 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1469 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1470 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1478 protected virtual void ResolveProbeType (ResolveContext rc)
1480 probe_type_expr = ProbeType.ResolveAsType (rc);
1483 public override void EmitSideEffect (EmitContext ec)
1485 expr.EmitSideEffect (ec);
1488 public override void FlowAnalysis (FlowAnalysisContext fc)
1490 expr.FlowAnalysis (fc);
1493 public override bool HasConditionalAccess ()
1495 return expr.HasConditionalAccess ();
1498 protected abstract string OperatorName { get; }
1500 protected override void CloneTo (CloneContext clonectx, Expression t)
1502 Probe target = (Probe) t;
1504 target.expr = expr.Clone (clonectx);
1505 target.ProbeType = ProbeType.Clone (clonectx);
1511 /// Implementation of the `is' operator.
1513 public class Is : Probe
1515 Nullable.Unwrap expr_unwrap;
1516 MethodSpec number_mg;
1517 Arguments number_args;
1519 public Is (Expression expr, Expression probe_type, Location l)
1520 : base (expr, probe_type, l)
1524 protected override string OperatorName {
1525 get { return "is"; }
1528 public LocalVariable Variable { get; set; }
1530 public override Expression CreateExpressionTree (ResolveContext ec)
1532 if (Variable != null)
1533 throw new NotSupportedException ();
1535 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1536 expr.CreateExpressionTree (ec),
1537 new TypeOf (probe_type_expr, loc));
1539 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1542 Expression CreateConstantResult (ResolveContext rc, bool result)
1545 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1546 probe_type_expr.GetSignatureForError ());
1548 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1549 probe_type_expr.GetSignatureForError ());
1551 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1552 return expr.IsSideEffectFree ?
1553 ReducedExpression.Create (c, this) :
1554 new SideEffectConstant (c, this, loc);
1557 public override void Emit (EmitContext ec)
1559 if (probe_type_expr == null) {
1560 if (ProbeType is WildcardPattern) {
1561 expr.EmitSideEffect (ec);
1562 ProbeType.Emit (ec);
1564 EmitPatternMatch (ec);
1571 if (expr_unwrap == null) {
1573 ec.Emit (OpCodes.Cgt_Un);
1577 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1579 if (probe_type_expr == null) {
1580 EmitPatternMatch (ec);
1585 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1588 void EmitPatternMatch (EmitContext ec)
1590 var no_match = ec.DefineLabel ();
1591 var end = ec.DefineLabel ();
1593 if (expr_unwrap != null) {
1594 expr_unwrap.EmitCheck (ec);
1596 if (ProbeType.IsNull) {
1598 ec.Emit (OpCodes.Ceq);
1602 ec.Emit (OpCodes.Brfalse_S, no_match);
1603 expr_unwrap.Emit (ec);
1604 ProbeType.Emit (ec);
1605 ec.Emit (OpCodes.Ceq);
1606 ec.Emit (OpCodes.Br_S, end);
1607 ec.MarkLabel (no_match);
1613 if (number_args != null && number_args.Count == 3) {
1614 var ce = new CallEmitter ();
1615 ce.Emit (ec, number_mg, number_args, loc);
1619 var probe_type = ProbeType.Type;
1622 ec.Emit (OpCodes.Isinst, probe_type);
1623 ec.Emit (OpCodes.Dup);
1624 ec.Emit (OpCodes.Brfalse, no_match);
1626 bool complex_pattern = ProbeType is ComplexPatternExpression;
1627 Label prev = ec.RecursivePatternLabel;
1628 if (complex_pattern)
1629 ec.RecursivePatternLabel = ec.DefineLabel ();
1631 if (number_mg != null) {
1632 var ce = new CallEmitter ();
1633 ce.Emit (ec, number_mg, number_args, loc);
1635 if (TypeSpec.IsValueType (probe_type))
1636 ec.Emit (OpCodes.Unbox_Any, probe_type);
1638 ProbeType.Emit (ec);
1639 if (complex_pattern) {
1642 ec.Emit (OpCodes.Ceq);
1645 ec.Emit (OpCodes.Br_S, end);
1646 ec.MarkLabel (no_match);
1648 ec.Emit (OpCodes.Pop);
1650 if (complex_pattern)
1651 ec.MarkLabel (ec.RecursivePatternLabel);
1653 ec.RecursivePatternLabel = prev;
1659 void EmitLoad (EmitContext ec)
1661 Label no_value_label = new Label ();
1663 if (expr_unwrap != null) {
1664 expr_unwrap.EmitCheck (ec);
1666 if (Variable == null)
1669 ec.Emit (OpCodes.Dup);
1670 no_value_label = ec.DefineLabel ();
1671 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1672 expr_unwrap.Emit (ec);
1676 // Only to make verifier happy
1677 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1678 ec.Emit (OpCodes.Box, expr.Type);
1680 ec.Emit (OpCodes.Isinst, probe_type_expr);
1683 if (Variable != null) {
1684 bool value_on_stack;
1685 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1686 ec.Emit (OpCodes.Dup);
1687 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1688 value_on_stack = true;
1690 value_on_stack = false;
1693 Variable.CreateBuilder (ec);
1694 Variable.EmitAssign (ec);
1696 if (expr_unwrap != null) {
1697 ec.MarkLabel (no_value_label);
1698 } else if (!value_on_stack) {
1704 protected override Expression DoResolve (ResolveContext rc)
1706 if (ResolveCommon (rc) == null)
1709 type = rc.BuiltinTypes.Bool;
1710 eclass = ExprClass.Value;
1712 if (probe_type_expr == null)
1713 return ResolveMatchingExpression (rc);
1715 var res = ResolveResultExpression (rc);
1716 if (Variable != null) {
1717 if (res is Constant)
1718 throw new NotImplementedException ("constant in type pattern matching");
1720 Variable.Type = probe_type_expr;
1721 var bc = rc as BlockContext;
1723 Variable.PrepareAssignmentAnalysis (bc);
1729 public override void FlowAnalysis (FlowAnalysisContext fc)
1731 base.FlowAnalysis (fc);
1733 if (Variable != null)
1734 fc.SetVariableAssigned (Variable.VariableInfo, true);
1737 protected override void ResolveProbeType (ResolveContext rc)
1739 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1740 if (ProbeType is PatternExpression) {
1741 ProbeType.Resolve (rc);
1746 // Have to use session recording because we don't have reliable type probing
1747 // mechanism (similar issue as in attributes resolving)
1749 // TODO: This is still wrong because ResolveAsType can be destructive
1751 var type_printer = new SessionReportPrinter ();
1752 var prev_recorder = rc.Report.SetPrinter (type_printer);
1754 probe_type_expr = ProbeType.ResolveAsType (rc);
1755 type_printer.EndSession ();
1757 if (probe_type_expr != null) {
1758 type_printer.Merge (rc.Report.Printer);
1759 rc.Report.SetPrinter (prev_recorder);
1763 var vexpr = ProbeType as VarExpr;
1764 if (vexpr != null && vexpr.InferType (rc, expr)) {
1765 probe_type_expr = vexpr.Type;
1766 rc.Report.SetPrinter (prev_recorder);
1770 var expr_printer = new SessionReportPrinter ();
1771 rc.Report.SetPrinter (expr_printer);
1772 ProbeType = ProbeType.Resolve (rc);
1773 expr_printer.EndSession ();
1775 if (ProbeType != null) {
1776 expr_printer.Merge (rc.Report.Printer);
1778 type_printer.Merge (rc.Report.Printer);
1781 rc.Report.SetPrinter (prev_recorder);
1785 base.ResolveProbeType (rc);
1788 Expression ResolveMatchingExpression (ResolveContext rc)
1790 var mc = ProbeType as Constant;
1792 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1793 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1798 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1800 var c = Expr as Constant;
1802 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1807 if (Expr.Type.IsNullableType) {
1808 expr_unwrap = new Nullable.Unwrap (Expr);
1809 expr_unwrap.Resolve (rc);
1810 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1811 } else if (ProbeType.Type == Expr.Type) {
1812 // TODO: Better error handling
1813 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1814 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1815 var helper = rc.Module.CreatePatterMatchingHelper ();
1816 number_mg = helper.NumberMatcher.Spec;
1819 // There are actually 3 arguments but the first one is already on the stack
1821 number_args = new Arguments (3);
1822 if (!ProbeType.Type.IsEnum)
1823 number_args.Add (new Argument (Expr));
1825 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1826 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1832 if (ProbeType is PatternExpression) {
1833 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1834 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1840 // TODO: Better error message
1841 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1845 Expression ResolveResultExpression (ResolveContext ec)
1847 TypeSpec d = expr.Type;
1848 bool d_is_nullable = false;
1851 // If E is a method group or the null literal, or if the type of E is a reference
1852 // type or a nullable type and the value of E is null, the result is false
1854 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1855 return CreateConstantResult (ec, false);
1857 if (d.IsNullableType) {
1858 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1859 if (!ut.IsGenericParameter) {
1861 d_is_nullable = true;
1865 TypeSpec t = probe_type_expr;
1866 bool t_is_nullable = false;
1867 if (t.IsNullableType) {
1868 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1869 if (!ut.IsGenericParameter) {
1871 t_is_nullable = true;
1878 // D and T are the same value types but D can be null
1880 if (d_is_nullable && !t_is_nullable) {
1881 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1886 // The result is true if D and T are the same value types
1888 return CreateConstantResult (ec, true);
1891 var tp = d as TypeParameterSpec;
1893 return ResolveGenericParameter (ec, t, tp);
1896 // An unboxing conversion exists
1898 if (Convert.ExplicitReferenceConversionExists (d, t))
1902 // open generic type
1904 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1907 var tps = t as TypeParameterSpec;
1909 return ResolveGenericParameter (ec, d, tps);
1911 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1912 ec.Report.Warning (1981, 3, loc,
1913 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1914 OperatorName, t.GetSignatureForError ());
1917 if (TypeManager.IsGenericParameter (d))
1918 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1920 if (TypeSpec.IsValueType (d)) {
1921 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1922 if (d_is_nullable && !t_is_nullable) {
1923 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1927 return CreateConstantResult (ec, true);
1930 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1931 var c = expr as Constant;
1933 return CreateConstantResult (ec, !c.IsNull);
1936 // Do not optimize for imported type or dynamic type
1938 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1939 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1943 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1947 // Turn is check into simple null check for implicitly convertible reference types
1949 return ReducedExpression.Create (
1950 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
1954 if (Convert.ExplicitReferenceConversionExists (d, t))
1958 // open generic type
1960 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1965 return CreateConstantResult (ec, false);
1968 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1970 if (t.IsReferenceType) {
1972 return CreateConstantResult (ec, false);
1975 if (expr.Type.IsGenericParameter) {
1976 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1977 return CreateConstantResult (ec, true);
1979 expr = new BoxedCast (expr, d);
1985 public override object Accept (StructuralVisitor visitor)
1987 return visitor.Visit (this);
1991 class WildcardPattern : PatternExpression
1993 public WildcardPattern (Location loc)
1998 protected override Expression DoResolve (ResolveContext rc)
2000 eclass = ExprClass.Value;
2001 type = rc.BuiltinTypes.Object;
2005 public override void Emit (EmitContext ec)
2011 class RecursivePattern : ComplexPatternExpression
2013 MethodGroupExpr operator_mg;
2014 Arguments operator_args;
2016 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2017 : base (typeExpresion, loc)
2019 Arguments = arguments;
2022 public Arguments Arguments { get; private set; }
2024 protected override Expression DoResolve (ResolveContext rc)
2026 type = TypeExpression.ResolveAsType (rc);
2030 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2031 if (operators == null) {
2032 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2036 var ops = FindMatchingOverloads (operators);
2038 // TODO: better error message
2039 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2044 Arguments.Resolve (rc, out dynamic_args);
2046 throw new NotImplementedException ("dynamic argument");
2048 var op = FindBestOverload (rc, ops);
2050 // TODO: better error message
2051 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2055 var op_types = op.Parameters.Types;
2056 operator_args = new Arguments (op_types.Length);
2057 operator_args.Add (new Argument (new EmptyExpression (type)));
2059 for (int i = 0; i < Arguments.Count; ++i) {
2060 // TODO: Needs releasing optimization
2061 var lt = new LocalTemporary (op_types [i + 1]);
2062 operator_args.Add (new Argument (lt, Argument.AType.Out));
2064 if (comparisons == null)
2065 comparisons = new Expression[Arguments.Count];
2070 var arg = Arguments [i];
2071 var named = arg as NamedArgument;
2072 if (named != null) {
2073 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2074 expr = Arguments [arg_comp_index].Expr;
2080 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2083 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2085 eclass = ExprClass.Value;
2089 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2091 int arg_count = Arguments.Count + 1;
2092 List<MethodSpec> best = null;
2093 foreach (MethodSpec method in members) {
2094 var pm = method.Parameters;
2095 if (pm.Count != arg_count)
2098 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2100 for (int ii = 1; ii < pm.Count; ++ii) {
2101 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2111 best = new List<MethodSpec> ();
2119 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2121 for (int ii = 0; ii < Arguments.Count; ++ii) {
2122 var arg = Arguments [ii];
2123 var expr = arg.Expr;
2124 if (expr is WildcardPattern)
2127 var na = arg as NamedArgument;
2128 for (int i = 0; i < methods.Count; ++i) {
2129 var pd = methods [i].Parameters;
2133 index = pd.GetParameterIndexByName (na.Name);
2135 methods.RemoveAt (i--);
2142 var m = pd.Types [index];
2143 if (!Convert.ImplicitConversionExists (rc, expr, m))
2144 methods.RemoveAt (i--);
2148 if (methods.Count != 1)
2154 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2156 operator_mg.EmitCall (ec, operator_args, false);
2157 ec.Emit (OpCodes.Brfalse, target);
2159 base.EmitBranchable (ec, target, on_true);
2162 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2164 if (expr is WildcardPattern)
2165 return new EmptyExpression (expr.Type);
2167 var recursive = expr as RecursivePattern;
2168 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2172 if (recursive != null) {
2173 recursive.SetParentInstance (lt);
2177 // TODO: Better error handling
2178 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2181 public void SetParentInstance (Expression instance)
2183 operator_args [0] = new Argument (instance);
2187 class PropertyPattern : ComplexPatternExpression
2189 LocalTemporary instance;
2191 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2192 : base (typeExpresion, loc)
2197 public List<PropertyPatternMember> Members { get; private set; }
2199 protected override Expression DoResolve (ResolveContext rc)
2201 type = TypeExpression.ResolveAsType (rc);
2205 comparisons = new Expression[Members.Count];
2207 // TODO: optimize when source is VariableReference, it'd save dup+pop
2208 instance = new LocalTemporary (type);
2210 for (int i = 0; i < Members.Count; i++) {
2211 var lookup = Members [i];
2213 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2214 if (member == null) {
2215 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2216 if (member != null) {
2217 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2222 if (member == null) {
2223 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2227 var pe = member as PropertyExpr;
2228 if (pe == null || member is FieldExpr) {
2229 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2233 // TODO: Obsolete checks
2234 // TODO: check accessibility
2235 if (pe != null && !pe.PropertyInfo.HasGet) {
2236 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2240 var expr = lookup.Expr.Resolve (rc);
2244 var me = (MemberExpr)member;
2245 me.InstanceExpression = instance;
2247 comparisons [i] = ResolveComparison (rc, expr, me);
2250 eclass = ExprClass.Value;
2254 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2256 if (expr is WildcardPattern)
2257 return new EmptyExpression (expr.Type);
2259 return new Is (instance, expr, expr.Location).Resolve (rc);
2262 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2264 instance.Store (ec);
2266 base.EmitBranchable (ec, target, on_true);
2270 class PropertyPatternMember
2272 public PropertyPatternMember (string name, Expression expr, Location loc)
2279 public string Name { get; private set; }
2280 public Expression Expr { get; private set; }
2281 public Location Location { get; private set; }
2284 abstract class PatternExpression : Expression
2286 protected PatternExpression (Location loc)
2291 public override Expression CreateExpressionTree (ResolveContext ec)
2293 throw new NotImplementedException ();
2297 abstract class ComplexPatternExpression : PatternExpression
2299 protected Expression[] comparisons;
2301 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2304 TypeExpression = typeExpresion;
2307 public ATypeNameExpression TypeExpression { get; private set; }
2309 public override void Emit (EmitContext ec)
2311 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2314 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2316 if (comparisons != null) {
2317 foreach (var comp in comparisons) {
2318 comp.EmitBranchable (ec, target, false);
2325 /// Implementation of the `as' operator.
2327 public class As : Probe {
2329 public As (Expression expr, Expression probe_type, Location l)
2330 : base (expr, probe_type, l)
2334 protected override string OperatorName {
2335 get { return "as"; }
2338 public override Expression CreateExpressionTree (ResolveContext ec)
2340 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2341 expr.CreateExpressionTree (ec),
2342 new TypeOf (probe_type_expr, loc));
2344 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2347 public override void Emit (EmitContext ec)
2351 ec.Emit (OpCodes.Isinst, type);
2353 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2354 ec.Emit (OpCodes.Unbox_Any, type);
2357 protected override Expression DoResolve (ResolveContext ec)
2359 if (ResolveCommon (ec) == null)
2362 type = probe_type_expr;
2363 eclass = ExprClass.Value;
2364 TypeSpec etype = expr.Type;
2366 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2367 if (TypeManager.IsGenericParameter (type)) {
2368 ec.Report.Error (413, loc,
2369 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2370 probe_type_expr.GetSignatureForError ());
2372 ec.Report.Error (77, loc,
2373 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2374 type.GetSignatureForError ());
2379 if (expr.IsNull && type.IsNullableType) {
2380 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2383 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2384 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2388 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2390 e = EmptyCast.Create (e, type);
2391 return ReducedExpression.Create (e, this).Resolve (ec);
2394 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2395 if (TypeManager.IsGenericParameter (etype))
2396 expr = new BoxedCast (expr, etype);
2401 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2402 expr = new BoxedCast (expr, etype);
2406 if (etype != InternalType.ErrorType) {
2407 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2408 etype.GetSignatureForError (), type.GetSignatureForError ());
2414 public override object Accept (StructuralVisitor visitor)
2416 return visitor.Visit (this);
2421 // This represents a typecast in the source language.
2423 public class Cast : ShimExpression {
2424 Expression target_type;
2426 public Cast (Expression cast_type, Expression expr, Location loc)
2429 this.target_type = cast_type;
2433 public Expression TargetType {
2434 get { return target_type; }
2437 protected override Expression DoResolve (ResolveContext ec)
2439 expr = expr.Resolve (ec);
2443 type = target_type.ResolveAsType (ec);
2447 if (type.IsStatic) {
2448 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2452 if (type.IsPointer && !ec.IsUnsafe) {
2453 UnsafeError (ec, loc);
2456 eclass = ExprClass.Value;
2458 Constant c = expr as Constant;
2460 c = c.Reduce (ec, type);
2465 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2467 return EmptyCast.Create (res, type);
2472 protected override void CloneTo (CloneContext clonectx, Expression t)
2474 Cast target = (Cast) t;
2476 target.target_type = target_type.Clone (clonectx);
2477 target.expr = expr.Clone (clonectx);
2480 public override object Accept (StructuralVisitor visitor)
2482 return visitor.Visit (this);
2486 public class ImplicitCast : ShimExpression
2490 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2493 this.loc = expr.Location;
2495 this.arrayAccess = arrayAccess;
2498 protected override Expression DoResolve (ResolveContext ec)
2500 expr = expr.Resolve (ec);
2505 expr = ConvertExpressionToArrayIndex (ec, expr);
2507 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2513 public class DeclarationExpression : Expression, IMemoryLocation
2515 LocalVariableReference lvr;
2517 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2519 VariableType = variableType;
2520 Variable = variable;
2521 this.loc = variable.Location;
2524 public LocalVariable Variable { get; set; }
2525 public Expression Initializer { get; set; }
2526 public FullNamedExpression VariableType { get; set; }
2528 public void AddressOf (EmitContext ec, AddressOp mode)
2530 Variable.CreateBuilder (ec);
2532 if (Initializer != null) {
2533 lvr.EmitAssign (ec, Initializer, false, false);
2536 lvr.AddressOf (ec, mode);
2539 protected override void CloneTo (CloneContext clonectx, Expression t)
2541 var target = (DeclarationExpression) t;
2543 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2545 if (Initializer != null)
2546 target.Initializer = Initializer.Clone (clonectx);
2549 public override Expression CreateExpressionTree (ResolveContext rc)
2551 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2555 bool DoResolveCommon (ResolveContext rc)
2557 var var_expr = VariableType as VarExpr;
2558 if (var_expr != null) {
2559 type = InternalType.VarOutType;
2561 type = VariableType.ResolveAsType (rc);
2566 if (Initializer != null) {
2567 Initializer = Initializer.Resolve (rc);
2569 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2570 type = var_expr.Type;
2574 Variable.Type = type;
2575 lvr = new LocalVariableReference (Variable, loc);
2577 eclass = ExprClass.Variable;
2581 protected override Expression DoResolve (ResolveContext rc)
2583 if (DoResolveCommon (rc))
2589 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2591 if (lvr == null && DoResolveCommon (rc))
2592 lvr.ResolveLValue (rc, right_side);
2597 public override void Emit (EmitContext ec)
2599 throw new NotImplementedException ();
2604 // C# 2.0 Default value expression
2606 public class DefaultValueExpression : Expression
2610 public DefaultValueExpression (Expression expr, Location loc)
2616 public Expression Expr {
2622 public override bool IsSideEffectFree {
2628 public override bool ContainsEmitWithAwait ()
2633 public override Expression CreateExpressionTree (ResolveContext ec)
2635 Arguments args = new Arguments (2);
2636 args.Add (new Argument (this));
2637 args.Add (new Argument (new TypeOf (type, loc)));
2638 return CreateExpressionFactoryCall (ec, "Constant", args);
2641 protected override Expression DoResolve (ResolveContext ec)
2643 type = expr.ResolveAsType (ec);
2647 if (type.IsStatic) {
2648 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2652 return new NullLiteral (Location).ConvertImplicitly (type);
2654 if (TypeSpec.IsReferenceType (type))
2655 return new NullConstant (type, loc);
2657 Constant c = New.Constantify (type, expr.Location);
2661 eclass = ExprClass.Variable;
2665 public override void Emit (EmitContext ec)
2667 LocalTemporary temp_storage = new LocalTemporary(type);
2669 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2670 ec.Emit(OpCodes.Initobj, type);
2671 temp_storage.Emit(ec);
2672 temp_storage.Release (ec);
2676 public override SLE.Expression MakeExpression (BuilderContext ctx)
2678 return SLE.Expression.Default (type.GetMetaInfo ());
2682 protected override void CloneTo (CloneContext clonectx, Expression t)
2684 DefaultValueExpression target = (DefaultValueExpression) t;
2686 target.expr = expr.Clone (clonectx);
2689 public override object Accept (StructuralVisitor visitor)
2691 return visitor.Visit (this);
2696 /// Binary operators
2698 public class Binary : Expression, IDynamicBinder
2700 public class PredefinedOperator
2702 protected readonly TypeSpec left;
2703 protected readonly TypeSpec right;
2704 protected readonly TypeSpec left_unwrap;
2705 protected readonly TypeSpec right_unwrap;
2706 public readonly Operator OperatorsMask;
2707 public TypeSpec ReturnType;
2709 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2710 : this (ltype, rtype, op_mask, ltype)
2714 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2715 : this (type, type, op_mask, return_type)
2719 public PredefinedOperator (TypeSpec type, Operator op_mask)
2720 : this (type, type, op_mask, type)
2724 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2726 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2727 throw new InternalErrorException ("Only masked values can be used");
2729 if ((op_mask & Operator.NullableMask) != 0) {
2730 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2731 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2733 left_unwrap = ltype;
2734 right_unwrap = rtype;
2739 this.OperatorsMask = op_mask;
2740 this.ReturnType = return_type;
2743 public bool IsLifted {
2745 return (OperatorsMask & Operator.NullableMask) != 0;
2749 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2753 var left_expr = b.left;
2754 var right_expr = b.right;
2756 b.type = ReturnType;
2759 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2760 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2761 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2764 if (right_expr.IsNull) {
2765 if ((b.oper & Operator.EqualityMask) != 0) {
2766 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2767 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2768 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2769 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2770 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2772 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2773 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2775 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2776 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2778 return b.CreateLiftedValueTypeResult (rc, left);
2780 } else if (left_expr.IsNull) {
2781 if ((b.oper & Operator.EqualityMask) != 0) {
2782 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2783 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2784 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2785 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2786 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2788 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2789 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2791 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2792 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2794 return b.CreateLiftedValueTypeResult (rc, right);
2800 // A user operators does not support multiple user conversions, but decimal type
2801 // is considered to be predefined type therefore we apply predefined operators rules
2802 // and then look for decimal user-operator implementation
2804 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2805 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2806 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2808 return b.ResolveUserOperator (rc, b.left, b.right);
2811 c = right_expr as Constant;
2813 if (c.IsDefaultValue) {
2817 // (expr + 0) to expr
2818 // (expr - 0) to expr
2819 // (bool? | false) to bool?
2821 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2822 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2823 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2824 return ReducedExpression.Create (b.left, b).Resolve (rc);
2828 // Optimizes (value &/&& 0) to 0
2830 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2831 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2832 return ReducedExpression.Create (side_effect, b);
2836 // Optimizes (bool? & true) to bool?
2838 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2839 return ReducedExpression.Create (b.left, b).Resolve (rc);
2843 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2844 return ReducedExpression.Create (b.left, b).Resolve (rc);
2846 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2847 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2851 c = b.left as Constant;
2853 if (c.IsDefaultValue) {
2857 // (0 + expr) to expr
2858 // (false | bool?) to bool?
2860 if (b.oper == Operator.Addition ||
2861 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2862 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2863 return ReducedExpression.Create (b.right, b).Resolve (rc);
2867 // Optimizes (false && expr) to false
2869 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2870 // No rhs side-effects
2871 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2872 return ReducedExpression.Create (c, b);
2876 // Optimizes (0 & value) to 0
2878 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2879 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2880 return ReducedExpression.Create (side_effect, b);
2884 // Optimizes (true & bool?) to bool?
2886 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2887 return ReducedExpression.Create (b.right, b).Resolve (rc);
2891 // Optimizes (true || expr) to true
2893 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2894 // No rhs side-effects
2895 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2896 return ReducedExpression.Create (c, b);
2900 if (b.oper == Operator.Multiply && c.IsOneInteger)
2901 return ReducedExpression.Create (b.right, b).Resolve (rc);
2905 var lifted = new Nullable.LiftedBinaryOperator (b);
2907 TypeSpec ltype, rtype;
2908 if (b.left.Type.IsNullableType) {
2909 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2910 ltype = left_unwrap;
2915 if (b.right.Type.IsNullableType) {
2916 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2917 rtype = right_unwrap;
2922 lifted.Left = b.left.IsNull ?
2923 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2924 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2926 lifted.Right = b.right.IsNull ?
2927 Nullable.LiftedNull.Create (rtype, b.right.Location) :
2928 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2930 return lifted.Resolve (rc);
2933 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2934 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2939 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2942 // We are dealing with primitive types only
2944 return left == ltype && ltype == rtype;
2947 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2950 if (left == lexpr.Type && right == rexpr.Type)
2953 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2954 Convert.ImplicitConversionExists (ec, rexpr, right);
2957 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2959 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2960 return best_operator;
2962 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2966 if (left != null && best_operator.left != null) {
2967 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2971 // When second argument is same as the first one, the result is same
2973 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2974 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2977 if (result == 0 || result > 2)
2980 return result == 1 ? best_operator : this;
2984 sealed class PredefinedStringOperator : PredefinedOperator
2986 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2987 : base (type, type, op_mask, retType)
2991 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2992 : base (ltype, rtype, op_mask, retType)
2996 public override Expression ConvertResult (ResolveContext ec, Binary b)
2999 // Use original expression for nullable arguments
3001 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3003 b.left = unwrap.Original;
3005 unwrap = b.right as Nullable.Unwrap;
3007 b.right = unwrap.Original;
3009 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3010 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3013 // Start a new concat expression using converted expression
3015 return StringConcat.Create (ec, b.left, b.right, b.loc);
3019 sealed class PredefinedEqualityOperator : PredefinedOperator
3021 MethodSpec equal_method, inequal_method;
3023 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3024 : base (arg, arg, Operator.EqualityMask, retType)
3028 public override Expression ConvertResult (ResolveContext ec, Binary b)
3030 b.type = ReturnType;
3032 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3033 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3035 Arguments args = new Arguments (2);
3036 args.Add (new Argument (b.left));
3037 args.Add (new Argument (b.right));
3040 if (b.oper == Operator.Equality) {
3041 if (equal_method == null) {
3042 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3043 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3044 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3045 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3047 throw new NotImplementedException (left.GetSignatureForError ());
3050 method = equal_method;
3052 if (inequal_method == null) {
3053 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3054 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3055 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3056 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3058 throw new NotImplementedException (left.GetSignatureForError ());
3061 method = inequal_method;
3064 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3068 class PredefinedPointerOperator : PredefinedOperator
3070 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3071 : base (ltype, rtype, op_mask)
3075 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3076 : base (ltype, rtype, op_mask, retType)
3080 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3081 : base (type, op_mask, return_type)
3085 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3088 if (!lexpr.Type.IsPointer)
3091 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3095 if (right == null) {
3096 if (!rexpr.Type.IsPointer)
3099 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3106 public override Expression ConvertResult (ResolveContext ec, Binary b)
3109 b.left = EmptyCast.Create (b.left, left);
3110 } else if (right != null) {
3111 b.right = EmptyCast.Create (b.right, right);
3114 TypeSpec r_type = ReturnType;
3115 Expression left_arg, right_arg;
3116 if (r_type == null) {
3119 right_arg = b.right;
3120 r_type = b.left.Type;
3124 r_type = b.right.Type;
3128 right_arg = b.right;
3131 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3136 public enum Operator {
3137 Multiply = 0 | ArithmeticMask,
3138 Division = 1 | ArithmeticMask,
3139 Modulus = 2 | ArithmeticMask,
3140 Addition = 3 | ArithmeticMask | AdditionMask,
3141 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3143 LeftShift = 5 | ShiftMask,
3144 RightShift = 6 | ShiftMask,
3146 LessThan = 7 | ComparisonMask | RelationalMask,
3147 GreaterThan = 8 | ComparisonMask | RelationalMask,
3148 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3149 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3150 Equality = 11 | ComparisonMask | EqualityMask,
3151 Inequality = 12 | ComparisonMask | EqualityMask,
3153 BitwiseAnd = 13 | BitwiseMask,
3154 ExclusiveOr = 14 | BitwiseMask,
3155 BitwiseOr = 15 | BitwiseMask,
3157 LogicalAnd = 16 | LogicalMask,
3158 LogicalOr = 17 | LogicalMask,
3163 ValuesOnlyMask = ArithmeticMask - 1,
3164 ArithmeticMask = 1 << 5,
3166 ComparisonMask = 1 << 7,
3167 EqualityMask = 1 << 8,
3168 BitwiseMask = 1 << 9,
3169 LogicalMask = 1 << 10,
3170 AdditionMask = 1 << 11,
3171 SubtractionMask = 1 << 12,
3172 RelationalMask = 1 << 13,
3174 DecomposedMask = 1 << 19,
3175 NullableMask = 1 << 20
3179 public enum State : byte
3183 UserOperatorsExcluded = 1 << 2
3186 readonly Operator oper;
3187 Expression left, right;
3189 ConvCast.Mode enum_conversion;
3191 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3192 : this (oper, left, right, State.Compound)
3196 public Binary (Operator oper, Expression left, Expression right, State state)
3197 : this (oper, left, right)
3202 public Binary (Operator oper, Expression left, Expression right)
3203 : this (oper, left, right, left.Location)
3207 public Binary (Operator oper, Expression left, Expression right, Location loc)
3217 public bool IsCompound {
3219 return (state & State.Compound) != 0;
3223 public Operator Oper {
3229 public Expression Left {
3235 public Expression Right {
3241 public override Location StartLocation {
3243 return left.StartLocation;
3250 /// Returns a stringified representation of the Operator
3252 string OperName (Operator oper)
3256 case Operator.Multiply:
3259 case Operator.Division:
3262 case Operator.Modulus:
3265 case Operator.Addition:
3268 case Operator.Subtraction:
3271 case Operator.LeftShift:
3274 case Operator.RightShift:
3277 case Operator.LessThan:
3280 case Operator.GreaterThan:
3283 case Operator.LessThanOrEqual:
3286 case Operator.GreaterThanOrEqual:
3289 case Operator.Equality:
3292 case Operator.Inequality:
3295 case Operator.BitwiseAnd:
3298 case Operator.BitwiseOr:
3301 case Operator.ExclusiveOr:
3304 case Operator.LogicalOr:
3307 case Operator.LogicalAnd:
3311 s = oper.ToString ();
3321 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3323 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3326 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3328 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3332 l = left.Type.GetSignatureForError ();
3333 r = right.Type.GetSignatureForError ();
3335 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3339 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3341 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3344 public override void FlowAnalysis (FlowAnalysisContext fc)
3347 // Optimized version when on-true/on-false data are not needed
3349 if ((oper & Operator.LogicalMask) == 0) {
3350 left.FlowAnalysis (fc);
3351 right.FlowAnalysis (fc);
3355 left.FlowAnalysisConditional (fc);
3356 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3357 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3359 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3360 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3361 right.FlowAnalysisConditional (fc);
3363 if (oper == Operator.LogicalOr)
3364 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3366 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3369 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3371 if ((oper & Operator.LogicalMask) == 0) {
3372 base.FlowAnalysisConditional (fc);
3376 left.FlowAnalysisConditional (fc);
3377 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3378 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3380 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3381 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3382 right.FlowAnalysisConditional (fc);
3384 var lc = left as Constant;
3385 if (oper == Operator.LogicalOr) {
3386 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3387 if (lc != null && lc.IsDefaultValue)
3388 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3390 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3392 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3393 if (lc != null && !lc.IsDefaultValue)
3394 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3396 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3401 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3403 string GetOperatorExpressionTypeName ()
3406 case Operator.Addition:
3407 return IsCompound ? "AddAssign" : "Add";
3408 case Operator.BitwiseAnd:
3409 return IsCompound ? "AndAssign" : "And";
3410 case Operator.BitwiseOr:
3411 return IsCompound ? "OrAssign" : "Or";
3412 case Operator.Division:
3413 return IsCompound ? "DivideAssign" : "Divide";
3414 case Operator.ExclusiveOr:
3415 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3416 case Operator.Equality:
3418 case Operator.GreaterThan:
3419 return "GreaterThan";
3420 case Operator.GreaterThanOrEqual:
3421 return "GreaterThanOrEqual";
3422 case Operator.Inequality:
3424 case Operator.LeftShift:
3425 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3426 case Operator.LessThan:
3428 case Operator.LessThanOrEqual:
3429 return "LessThanOrEqual";
3430 case Operator.LogicalAnd:
3432 case Operator.LogicalOr:
3434 case Operator.Modulus:
3435 return IsCompound ? "ModuloAssign" : "Modulo";
3436 case Operator.Multiply:
3437 return IsCompound ? "MultiplyAssign" : "Multiply";
3438 case Operator.RightShift:
3439 return IsCompound ? "RightShiftAssign" : "RightShift";
3440 case Operator.Subtraction:
3441 return IsCompound ? "SubtractAssign" : "Subtract";
3443 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3447 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3450 case Operator.Addition:
3451 return CSharp.Operator.OpType.Addition;
3452 case Operator.BitwiseAnd:
3453 case Operator.LogicalAnd:
3454 return CSharp.Operator.OpType.BitwiseAnd;
3455 case Operator.BitwiseOr:
3456 case Operator.LogicalOr:
3457 return CSharp.Operator.OpType.BitwiseOr;
3458 case Operator.Division:
3459 return CSharp.Operator.OpType.Division;
3460 case Operator.Equality:
3461 return CSharp.Operator.OpType.Equality;
3462 case Operator.ExclusiveOr:
3463 return CSharp.Operator.OpType.ExclusiveOr;
3464 case Operator.GreaterThan:
3465 return CSharp.Operator.OpType.GreaterThan;
3466 case Operator.GreaterThanOrEqual:
3467 return CSharp.Operator.OpType.GreaterThanOrEqual;
3468 case Operator.Inequality:
3469 return CSharp.Operator.OpType.Inequality;
3470 case Operator.LeftShift:
3471 return CSharp.Operator.OpType.LeftShift;
3472 case Operator.LessThan:
3473 return CSharp.Operator.OpType.LessThan;
3474 case Operator.LessThanOrEqual:
3475 return CSharp.Operator.OpType.LessThanOrEqual;
3476 case Operator.Modulus:
3477 return CSharp.Operator.OpType.Modulus;
3478 case Operator.Multiply:
3479 return CSharp.Operator.OpType.Multiply;
3480 case Operator.RightShift:
3481 return CSharp.Operator.OpType.RightShift;
3482 case Operator.Subtraction:
3483 return CSharp.Operator.OpType.Subtraction;
3485 throw new InternalErrorException (op.ToString ());
3489 public override bool ContainsEmitWithAwait ()
3491 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3494 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3499 case Operator.Multiply:
3500 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3501 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3502 opcode = OpCodes.Mul_Ovf;
3503 else if (!IsFloat (l))
3504 opcode = OpCodes.Mul_Ovf_Un;
3506 opcode = OpCodes.Mul;
3508 opcode = OpCodes.Mul;
3512 case Operator.Division:
3514 opcode = OpCodes.Div_Un;
3516 opcode = OpCodes.Div;
3519 case Operator.Modulus:
3521 opcode = OpCodes.Rem_Un;
3523 opcode = OpCodes.Rem;
3526 case Operator.Addition:
3527 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3528 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3529 opcode = OpCodes.Add_Ovf;
3530 else if (!IsFloat (l))
3531 opcode = OpCodes.Add_Ovf_Un;
3533 opcode = OpCodes.Add;
3535 opcode = OpCodes.Add;
3538 case Operator.Subtraction:
3539 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3540 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3541 opcode = OpCodes.Sub_Ovf;
3542 else if (!IsFloat (l))
3543 opcode = OpCodes.Sub_Ovf_Un;
3545 opcode = OpCodes.Sub;
3547 opcode = OpCodes.Sub;
3550 case Operator.RightShift:
3551 if (!(right is IntConstant)) {
3552 ec.EmitInt (GetShiftMask (l));
3553 ec.Emit (OpCodes.And);
3557 opcode = OpCodes.Shr_Un;
3559 opcode = OpCodes.Shr;
3562 case Operator.LeftShift:
3563 if (!(right is IntConstant)) {
3564 ec.EmitInt (GetShiftMask (l));
3565 ec.Emit (OpCodes.And);
3568 opcode = OpCodes.Shl;
3571 case Operator.Equality:
3572 opcode = OpCodes.Ceq;
3575 case Operator.Inequality:
3576 ec.Emit (OpCodes.Ceq);
3579 opcode = OpCodes.Ceq;
3582 case Operator.LessThan:
3584 opcode = OpCodes.Clt_Un;
3586 opcode = OpCodes.Clt;
3589 case Operator.GreaterThan:
3591 opcode = OpCodes.Cgt_Un;
3593 opcode = OpCodes.Cgt;
3596 case Operator.LessThanOrEqual:
3597 if (IsUnsigned (l) || IsFloat (l))
3598 ec.Emit (OpCodes.Cgt_Un);
3600 ec.Emit (OpCodes.Cgt);
3603 opcode = OpCodes.Ceq;
3606 case Operator.GreaterThanOrEqual:
3607 if (IsUnsigned (l) || IsFloat (l))
3608 ec.Emit (OpCodes.Clt_Un);
3610 ec.Emit (OpCodes.Clt);
3614 opcode = OpCodes.Ceq;
3617 case Operator.BitwiseOr:
3618 opcode = OpCodes.Or;
3621 case Operator.BitwiseAnd:
3622 opcode = OpCodes.And;
3625 case Operator.ExclusiveOr:
3626 opcode = OpCodes.Xor;
3630 throw new InternalErrorException (oper.ToString ());
3636 static int GetShiftMask (TypeSpec type)
3638 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3641 static bool IsUnsigned (TypeSpec t)
3643 switch (t.BuiltinType) {
3644 case BuiltinTypeSpec.Type.Char:
3645 case BuiltinTypeSpec.Type.UInt:
3646 case BuiltinTypeSpec.Type.ULong:
3647 case BuiltinTypeSpec.Type.UShort:
3648 case BuiltinTypeSpec.Type.Byte:
3655 static bool IsFloat (TypeSpec t)
3657 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3660 public Expression ResolveOperator (ResolveContext rc)
3662 eclass = ExprClass.Value;
3664 TypeSpec l = left.Type;
3665 TypeSpec r = right.Type;
3667 bool primitives_only = false;
3670 // Handles predefined primitive types
3672 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3673 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3674 if ((oper & Operator.ShiftMask) == 0) {
3675 if (!DoBinaryOperatorPromotion (rc))
3678 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3682 if (l.IsPointer || r.IsPointer)
3683 return ResolveOperatorPointer (rc, l, r);
3686 if ((state & State.UserOperatorsExcluded) == 0) {
3687 expr = ResolveUserOperator (rc, left, right);
3692 bool lenum = l.IsEnum;
3693 bool renum = r.IsEnum;
3694 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3698 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3699 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3704 if ((oper & Operator.BitwiseMask) != 0) {
3705 expr = EmptyCast.Create (expr, type);
3706 enum_conversion = GetEnumResultCast (type);
3708 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3709 expr = OptimizeAndOperation (expr);
3713 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3714 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3717 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3718 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3722 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3725 // We cannot break here there is also Enum + String possible match
3726 // which is not ambiguous with predefined enum operators
3729 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3730 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3734 } else if (l.IsDelegate || r.IsDelegate) {
3738 expr = ResolveOperatorDelegate (rc, l, r);
3740 // TODO: Can this be ambiguous
3748 // Equality operators are more complicated
3750 if ((oper & Operator.EqualityMask) != 0) {
3751 return ResolveEquality (rc, l, r, primitives_only);
3754 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3758 if (primitives_only)
3762 // Lifted operators have lower priority
3764 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3767 static bool IsEnumOrNullableEnum (TypeSpec type)
3769 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3773 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3774 // if 'left' is not an enumeration constant, create one from the type of 'right'
3775 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3778 case Operator.BitwiseOr:
3779 case Operator.BitwiseAnd:
3780 case Operator.ExclusiveOr:
3781 case Operator.Equality:
3782 case Operator.Inequality:
3783 case Operator.LessThan:
3784 case Operator.LessThanOrEqual:
3785 case Operator.GreaterThan:
3786 case Operator.GreaterThanOrEqual:
3787 if (left.Type.IsEnum)
3790 if (left.IsZeroInteger)
3791 return left.Reduce (ec, right.Type);
3795 case Operator.Addition:
3796 case Operator.Subtraction:
3799 case Operator.Multiply:
3800 case Operator.Division:
3801 case Operator.Modulus:
3802 case Operator.LeftShift:
3803 case Operator.RightShift:
3804 if (right.Type.IsEnum || left.Type.IsEnum)
3813 // The `|' operator used on types which were extended is dangerous
3815 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3817 OpcodeCast lcast = left as OpcodeCast;
3818 if (lcast != null) {
3819 if (IsUnsigned (lcast.UnderlyingType))
3823 OpcodeCast rcast = right as OpcodeCast;
3824 if (rcast != null) {
3825 if (IsUnsigned (rcast.UnderlyingType))
3829 if (lcast == null && rcast == null)
3832 // FIXME: consider constants
3834 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3835 ec.Report.Warning (675, 3, loc,
3836 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3837 ltype.GetSignatureForError ());
3840 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3842 return new PredefinedOperator[] {
3844 // Pointer arithmetic:
3846 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3847 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3848 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3849 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3851 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3852 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3853 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3854 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3857 // T* operator + (int y, T* x);
3858 // T* operator + (uint y, T *x);
3859 // T* operator + (long y, T *x);
3860 // T* operator + (ulong y, T *x);
3862 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3863 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3864 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3865 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3868 // long operator - (T* x, T *y)
3870 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3874 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3876 TypeSpec bool_type = types.Bool;
3879 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3880 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3881 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3882 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3883 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3884 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3885 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3887 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3888 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3889 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3890 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3891 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3892 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3893 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3895 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3896 // Remaining string operators are in lifted tables
3898 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3900 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3901 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3902 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3906 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3908 var types = module.Compiler.BuiltinTypes;
3911 // Not strictly lifted but need to be in second group otherwise expressions like
3912 // int + null would resolve to +(object, string) instead of +(int?, int?)
3914 var string_operators = new [] {
3915 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3916 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3919 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3920 if (nullable == null)
3921 return string_operators;
3923 var bool_type = types.Bool;
3925 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3926 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3927 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3928 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3929 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3930 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3931 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3932 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3935 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3936 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3937 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3938 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3939 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3940 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3941 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3943 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3944 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3945 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3946 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3947 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3948 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3949 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3951 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3953 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3954 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3955 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3957 string_operators [0],
3958 string_operators [1]
3962 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3964 TypeSpec bool_type = types.Bool;
3967 new PredefinedEqualityOperator (types.String, bool_type),
3968 new PredefinedEqualityOperator (types.Delegate, bool_type),
3969 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3970 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3971 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3972 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3973 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3975 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3976 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3980 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3982 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3984 if (nullable == null)
3985 return new PredefinedOperator [0];
3987 var types = module.Compiler.BuiltinTypes;
3988 var bool_type = types.Bool;
3989 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3990 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3991 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3992 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3993 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3994 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3995 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3996 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3999 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4000 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4001 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4002 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4003 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4004 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4005 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4006 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4011 // 7.2.6.2 Binary numeric promotions
4013 bool DoBinaryOperatorPromotion (ResolveContext rc)
4015 TypeSpec ltype = left.Type;
4016 if (ltype.IsNullableType) {
4017 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4021 // This is numeric promotion code only
4023 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4026 TypeSpec rtype = right.Type;
4027 if (rtype.IsNullableType) {
4028 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4031 var lb = ltype.BuiltinType;
4032 var rb = rtype.BuiltinType;
4036 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4037 type = rc.BuiltinTypes.Decimal;
4038 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4039 type = rc.BuiltinTypes.Double;
4040 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4041 type = rc.BuiltinTypes.Float;
4042 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4043 type = rc.BuiltinTypes.ULong;
4045 if (IsSignedType (lb)) {
4046 expr = ConvertSignedConstant (left, type);
4050 } else if (IsSignedType (rb)) {
4051 expr = ConvertSignedConstant (right, type);
4057 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4058 type = rc.BuiltinTypes.Long;
4059 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4060 type = rc.BuiltinTypes.UInt;
4062 if (IsSignedType (lb)) {
4063 expr = ConvertSignedConstant (left, type);
4065 type = rc.BuiltinTypes.Long;
4066 } else if (IsSignedType (rb)) {
4067 expr = ConvertSignedConstant (right, type);
4069 type = rc.BuiltinTypes.Long;
4072 type = rc.BuiltinTypes.Int;
4075 if (ltype != type) {
4076 expr = PromoteExpression (rc, left, type);
4083 if (rtype != type) {
4084 expr = PromoteExpression (rc, right, type);
4094 static bool IsSignedType (BuiltinTypeSpec.Type type)
4097 case BuiltinTypeSpec.Type.Int:
4098 case BuiltinTypeSpec.Type.Short:
4099 case BuiltinTypeSpec.Type.SByte:
4100 case BuiltinTypeSpec.Type.Long:
4107 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4109 var c = expr as Constant;
4113 return c.ConvertImplicitly (type);
4116 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4118 if (expr.Type.IsNullableType) {
4119 return Convert.ImplicitConversionStandard (rc, expr,
4120 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4123 var c = expr as Constant;
4125 return c.ConvertImplicitly (type);
4127 return Convert.ImplicitNumericConversion (expr, type);
4130 protected override Expression DoResolve (ResolveContext ec)
4135 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4136 left = ((ParenthesizedExpression) left).Expr;
4137 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4141 if (left.eclass == ExprClass.Type) {
4142 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4146 left = left.Resolve (ec);
4151 right = right.Resolve (ec);
4155 Constant lc = left as Constant;
4156 Constant rc = right as Constant;
4158 // The conversion rules are ignored in enum context but why
4159 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4160 lc = EnumLiftUp (ec, lc, rc);
4162 rc = EnumLiftUp (ec, rc, lc);
4165 if (rc != null && lc != null) {
4166 int prev_e = ec.Report.Errors;
4167 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4168 if (e != null || ec.Report.Errors != prev_e)
4172 // Comparison warnings
4173 if ((oper & Operator.ComparisonMask) != 0) {
4174 if (left.Equals (right)) {
4175 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4177 CheckOutOfRangeComparison (ec, lc, right.Type);
4178 CheckOutOfRangeComparison (ec, rc, left.Type);
4181 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4182 return DoResolveDynamic (ec);
4184 return DoResolveCore (ec, left, right);
4187 Expression DoResolveDynamic (ResolveContext rc)
4190 var rt = right.Type;
4191 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4192 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4193 Error_OperatorCannotBeApplied (rc, left, right);
4200 // Special handling for logical boolean operators which require rhs not to be
4201 // evaluated based on lhs value
4203 if ((oper & Operator.LogicalMask) != 0) {
4204 Expression cond_left, cond_right, expr;
4206 args = new Arguments (2);
4208 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4209 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4211 var cond_args = new Arguments (1);
4212 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4215 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4216 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4218 left = temp.CreateReferenceExpression (rc, loc);
4219 if (oper == Operator.LogicalAnd) {
4220 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4223 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4227 args.Add (new Argument (left));
4228 args.Add (new Argument (right));
4229 cond_right = new DynamicExpressionStatement (this, args, loc);
4231 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4233 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4234 rc.Report.Error (7083, left.Location,
4235 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4236 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4240 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4241 args.Add (new Argument (right));
4242 right = new DynamicExpressionStatement (this, args, loc);
4245 // bool && dynamic => (temp = left) ? temp && right : temp;
4246 // bool || dynamic => (temp = left) ? temp : temp || right;
4248 if (oper == Operator.LogicalAnd) {
4250 cond_right = temp.CreateReferenceExpression (rc, loc);
4252 cond_left = temp.CreateReferenceExpression (rc, loc);
4256 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4259 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4262 args = new Arguments (2);
4263 args.Add (new Argument (left));
4264 args.Add (new Argument (right));
4265 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4268 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4270 Expression expr = ResolveOperator (ec);
4272 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4274 if (left == null || right == null)
4275 throw new InternalErrorException ("Invalid conversion");
4277 if (oper == Operator.BitwiseOr)
4278 CheckBitwiseOrOnSignExtended (ec);
4283 public override SLE.Expression MakeExpression (BuilderContext ctx)
4285 return MakeExpression (ctx, left, right);
4288 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4290 var le = left.MakeExpression (ctx);
4291 var re = right.MakeExpression (ctx);
4292 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4295 case Operator.Addition:
4296 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4297 case Operator.BitwiseAnd:
4298 return SLE.Expression.And (le, re);
4299 case Operator.BitwiseOr:
4300 return SLE.Expression.Or (le, re);
4301 case Operator.Division:
4302 return SLE.Expression.Divide (le, re);
4303 case Operator.Equality:
4304 return SLE.Expression.Equal (le, re);
4305 case Operator.ExclusiveOr:
4306 return SLE.Expression.ExclusiveOr (le, re);
4307 case Operator.GreaterThan:
4308 return SLE.Expression.GreaterThan (le, re);
4309 case Operator.GreaterThanOrEqual:
4310 return SLE.Expression.GreaterThanOrEqual (le, re);
4311 case Operator.Inequality:
4312 return SLE.Expression.NotEqual (le, re);
4313 case Operator.LeftShift:
4314 return SLE.Expression.LeftShift (le, re);
4315 case Operator.LessThan:
4316 return SLE.Expression.LessThan (le, re);
4317 case Operator.LessThanOrEqual:
4318 return SLE.Expression.LessThanOrEqual (le, re);
4319 case Operator.LogicalAnd:
4320 return SLE.Expression.AndAlso (le, re);
4321 case Operator.LogicalOr:
4322 return SLE.Expression.OrElse (le, re);
4323 case Operator.Modulus:
4324 return SLE.Expression.Modulo (le, re);
4325 case Operator.Multiply:
4326 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4327 case Operator.RightShift:
4328 return SLE.Expression.RightShift (le, re);
4329 case Operator.Subtraction:
4330 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4332 throw new NotImplementedException (oper.ToString ());
4337 // D operator + (D x, D y)
4338 // D operator - (D x, D y)
4340 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4342 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4344 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4345 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4350 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4351 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4361 MethodSpec method = null;
4362 Arguments args = new Arguments (2);
4363 args.Add (new Argument (left));
4364 args.Add (new Argument (right));
4366 if (oper == Operator.Addition) {
4367 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4368 } else if (oper == Operator.Subtraction) {
4369 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4373 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4375 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4376 return new ClassCast (expr, l);
4380 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4382 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
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);
4390 // bool operator >= (E x, E y);
4392 // E operator & (E x, E y);
4393 // E operator | (E x, E y);
4394 // E operator ^ (E x, E y);
4397 if ((oper & Operator.ComparisonMask) != 0) {
4398 type = rc.BuiltinTypes.Bool;
4404 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4410 if (ltype == rtype) {
4414 var lifted = new Nullable.LiftedBinaryOperator (this);
4416 lifted.Right = right;
4417 return lifted.Resolve (rc);
4420 if (renum && !ltype.IsNullableType) {
4421 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4426 } else if (lenum && !rtype.IsNullableType) {
4427 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4435 // Now try lifted version of predefined operator
4437 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4438 if (nullable_type != null) {
4439 if (renum && !ltype.IsNullableType) {
4440 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4442 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4445 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4448 if ((oper & Operator.BitwiseMask) != 0)
4452 if ((oper & Operator.BitwiseMask) != 0)
4453 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4455 return CreateLiftedValueTypeResult (rc, rtype);
4459 var lifted = new Nullable.LiftedBinaryOperator (this);
4461 lifted.Right = right;
4462 return lifted.Resolve (rc);
4464 } else if (lenum && !rtype.IsNullableType) {
4465 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4467 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4470 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4473 if ((oper & Operator.BitwiseMask) != 0)
4477 if ((oper & Operator.BitwiseMask) != 0)
4478 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4480 return CreateLiftedValueTypeResult (rc, ltype);
4484 var lifted = new Nullable.LiftedBinaryOperator (this);
4486 lifted.Right = expr;
4487 return lifted.Resolve (rc);
4489 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4490 Nullable.Unwrap unwrap = null;
4491 if (left.IsNull || right.IsNull) {
4492 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4493 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4495 if ((oper & Operator.RelationalMask) != 0)
4496 return CreateLiftedValueTypeResult (rc, rtype);
4498 if ((oper & Operator.BitwiseMask) != 0)
4499 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4502 return CreateLiftedValueTypeResult (rc, left.Type);
4504 // Equality operators are valid between E? and null
4506 unwrap = new Nullable.Unwrap (right);
4508 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4512 if ((oper & Operator.BitwiseMask) != 0)
4517 var lifted = new Nullable.LiftedBinaryOperator (this);
4519 lifted.Right = right;
4520 lifted.UnwrapRight = unwrap;
4521 return lifted.Resolve (rc);
4523 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4524 Nullable.Unwrap unwrap = null;
4525 if (right.IsNull || left.IsNull) {
4526 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4527 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4529 if ((oper & Operator.RelationalMask) != 0)
4530 return CreateLiftedValueTypeResult (rc, ltype);
4532 if ((oper & Operator.BitwiseMask) != 0)
4533 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4536 return CreateLiftedValueTypeResult (rc, right.Type);
4538 // Equality operators are valid between E? and null
4540 unwrap = new Nullable.Unwrap (left);
4542 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4546 if ((oper & Operator.BitwiseMask) != 0)
4551 var lifted = new Nullable.LiftedBinaryOperator (this);
4553 lifted.UnwrapLeft = unwrap;
4554 lifted.Right = expr;
4555 return lifted.Resolve (rc);
4563 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4565 TypeSpec underlying_type;
4566 if (expr.Type.IsNullableType) {
4567 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4569 underlying_type = EnumSpec.GetUnderlyingType (nt);
4571 underlying_type = nt;
4572 } else if (expr.Type.IsEnum) {
4573 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4575 underlying_type = expr.Type;
4578 switch (underlying_type.BuiltinType) {
4579 case BuiltinTypeSpec.Type.SByte:
4580 case BuiltinTypeSpec.Type.Byte:
4581 case BuiltinTypeSpec.Type.Short:
4582 case BuiltinTypeSpec.Type.UShort:
4583 underlying_type = rc.BuiltinTypes.Int;
4587 if (expr.Type.IsNullableType || liftType)
4588 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4590 if (expr.Type == underlying_type)
4593 return EmptyCast.Create (expr, underlying_type);
4596 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4599 // U operator - (E e, E f)
4600 // E operator - (E e, U x) // Internal decomposition operator
4601 // E operator - (U x, E e) // Internal decomposition operator
4603 // E operator + (E e, U x)
4604 // E operator + (U x, E e)
4613 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4619 if (!enum_type.IsNullableType) {
4620 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4622 if (oper == Operator.Subtraction)
4623 expr = ConvertEnumSubtractionResult (rc, expr);
4625 expr = ConvertEnumAdditionalResult (expr, enum_type);
4627 enum_conversion = GetEnumResultCast (expr.Type);
4632 var nullable = rc.Module.PredefinedTypes.Nullable;
4635 // Don't try nullable version when nullable type is undefined
4637 if (!nullable.IsDefined)
4640 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4643 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4645 if (oper == Operator.Subtraction)
4646 expr = ConvertEnumSubtractionResult (rc, expr);
4648 expr = ConvertEnumAdditionalResult (expr, enum_type);
4650 enum_conversion = GetEnumResultCast (expr.Type);
4656 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4658 return EmptyCast.Create (expr, enumType);
4661 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4664 // Enumeration subtraction has different result type based on
4667 TypeSpec result_type;
4668 if (left.Type == right.Type) {
4669 var c = right as EnumConstant;
4670 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4672 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4673 // E which is not what expressions E - 1 or 0 - E return
4675 result_type = left.Type;
4677 result_type = left.Type.IsNullableType ?
4678 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4679 EnumSpec.GetUnderlyingType (left.Type);
4682 if (IsEnumOrNullableEnum (left.Type)) {
4683 result_type = left.Type;
4685 result_type = right.Type;
4688 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4689 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4692 return EmptyCast.Create (expr, result_type);
4695 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4697 if (type.IsNullableType)
4698 type = Nullable.NullableInfo.GetUnderlyingType (type);
4701 type = EnumSpec.GetUnderlyingType (type);
4703 switch (type.BuiltinType) {
4704 case BuiltinTypeSpec.Type.SByte:
4705 return ConvCast.Mode.I4_I1;
4706 case BuiltinTypeSpec.Type.Byte:
4707 return ConvCast.Mode.I4_U1;
4708 case BuiltinTypeSpec.Type.Short:
4709 return ConvCast.Mode.I4_I2;
4710 case BuiltinTypeSpec.Type.UShort:
4711 return ConvCast.Mode.I4_U2;
4718 // Equality operators rules
4720 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4723 type = ec.BuiltinTypes.Bool;
4724 bool no_arg_conv = false;
4726 if (!primitives_only) {
4729 // a, Both operands are reference-type values or the value null
4730 // b, One operand is a value of type T where T is a type-parameter and
4731 // the other operand is the value null. Furthermore T does not have the
4732 // value type constraint
4734 // LAMESPEC: Very confusing details in the specification, basically any
4735 // reference like type-parameter is allowed
4737 var tparam_l = l as TypeParameterSpec;
4738 var tparam_r = r as TypeParameterSpec;
4739 if (tparam_l != null) {
4740 if (right is NullLiteral) {
4741 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4744 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4748 if (!tparam_l.IsReferenceType)
4751 l = tparam_l.GetEffectiveBase ();
4752 left = new BoxedCast (left, l);
4753 } else if (left is NullLiteral && tparam_r == null) {
4754 if (TypeSpec.IsReferenceType (r))
4757 if (r.Kind == MemberKind.InternalCompilerType)
4761 if (tparam_r != null) {
4762 if (left is NullLiteral) {
4763 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4766 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4770 if (!tparam_r.IsReferenceType)
4773 r = tparam_r.GetEffectiveBase ();
4774 right = new BoxedCast (right, r);
4775 } else if (right is NullLiteral) {
4776 if (TypeSpec.IsReferenceType (l))
4779 if (l.Kind == MemberKind.InternalCompilerType)
4784 // LAMESPEC: method groups can be compared when they convert to other side delegate
4787 if (right.eclass == ExprClass.MethodGroup) {
4788 result = Convert.ImplicitConversion (ec, right, l, loc);
4794 } else if (r.IsDelegate && l != r) {
4797 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4798 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4805 no_arg_conv = l == r && !l.IsStruct;
4810 // bool operator != (string a, string b)
4811 // bool operator == (string a, string b)
4813 // bool operator != (Delegate a, Delegate b)
4814 // bool operator == (Delegate a, Delegate b)
4816 // bool operator != (bool a, bool b)
4817 // bool operator == (bool a, bool b)
4819 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4820 // they implement an implicit conversion to any of types above. This does
4821 // not apply when both operands are of same reference type
4823 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4824 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4829 // Now try lifted version of predefined operators
4831 if (no_arg_conv && !l.IsNullableType) {
4833 // Optimizes cases which won't match
4836 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4842 // The == and != operators permit one operand to be a value of a nullable
4843 // type and the other to be the null literal, even if no predefined or user-defined
4844 // operator (in unlifted or lifted form) exists for the operation.
4846 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4847 var lifted = new Nullable.LiftedBinaryOperator (this);
4849 lifted.Right = right;
4850 return lifted.Resolve (ec);
4855 // bool operator != (object a, object b)
4856 // bool operator == (object a, object b)
4858 // An explicit reference conversion exists from the
4859 // type of either operand to the type of the other operand.
4862 // Optimize common path
4864 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4867 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4868 !Convert.ExplicitReferenceConversionExists (r, l))
4871 // Reject allowed explicit conversions like int->object
4872 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4875 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4876 ec.Report.Warning (253, 2, loc,
4877 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4878 l.GetSignatureForError ());
4880 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4881 ec.Report.Warning (252, 2, loc,
4882 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4883 r.GetSignatureForError ());
4889 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
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);
4897 // bool operator >= (void* x, void* y);
4899 if ((oper & Operator.ComparisonMask) != 0) {
4902 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4909 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4915 type = ec.BuiltinTypes.Bool;
4919 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4923 // Build-in operators method overloading
4925 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4927 PredefinedOperator best_operator = null;
4928 TypeSpec l = left.Type;
4929 TypeSpec r = right.Type;
4930 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4932 foreach (PredefinedOperator po in operators) {
4933 if ((po.OperatorsMask & oper_mask) == 0)
4936 if (primitives_only) {
4937 if (!po.IsPrimitiveApplicable (l, r))
4940 if (!po.IsApplicable (ec, left, right))
4944 if (best_operator == null) {
4946 if (primitives_only)
4952 best_operator = po.ResolveBetterOperator (ec, best_operator);
4954 if (best_operator == null) {
4955 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4956 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4963 if (best_operator == null)
4966 return best_operator.ConvertResult (ec, this);
4970 // Optimize & constant expressions with 0 value
4972 Expression OptimizeAndOperation (Expression expr)
4974 Constant rc = right as Constant;
4975 Constant lc = left as Constant;
4976 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4978 // The result is a constant with side-effect
4980 Constant side_effect = rc == null ?
4981 new SideEffectConstant (lc, right, loc) :
4982 new SideEffectConstant (rc, left, loc);
4984 return ReducedExpression.Create (side_effect, expr);
4991 // Value types can be compared with the null literal because of the lifting
4992 // language rules. However the result is always true or false.
4994 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4996 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4997 type = rc.BuiltinTypes.Bool;
5001 // FIXME: Handle side effect constants
5002 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5004 if ((Oper & Operator.EqualityMask) != 0) {
5005 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5006 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5008 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5009 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5016 // Performs user-operator overloading
5018 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5020 Expression oper_expr;
5022 var op = ConvertBinaryToUserOperator (oper);
5024 if (l.IsNullableType)
5025 l = Nullable.NullableInfo.GetUnderlyingType (l);
5027 if (r.IsNullableType)
5028 r = Nullable.NullableInfo.GetUnderlyingType (r);
5030 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5031 IList<MemberSpec> right_operators = null;
5034 right_operators = MemberCache.GetUserOperator (r, op, false);
5035 if (right_operators == null && left_operators == null)
5037 } else if (left_operators == null) {
5041 Arguments args = new Arguments (2);
5042 Argument larg = new Argument (left);
5044 Argument rarg = new Argument (right);
5048 // User-defined operator implementations always take precedence
5049 // over predefined operator implementations
5051 if (left_operators != null && right_operators != null) {
5052 left_operators = CombineUserOperators (left_operators, right_operators);
5053 } else if (right_operators != null) {
5054 left_operators = right_operators;
5057 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5058 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5060 var res = new OverloadResolver (left_operators, restr, loc);
5062 var oper_method = res.ResolveOperator (rc, ref args);
5063 if (oper_method == null) {
5065 // Logical && and || cannot be lifted
5067 if ((oper & Operator.LogicalMask) != 0)
5071 // Apply lifted user operators only for liftable types. Implicit conversion
5072 // to nullable types is not allowed
5074 if (!IsLiftedOperatorApplicable ())
5077 // TODO: Cache the result in module container
5078 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5079 if (lifted_methods == null)
5082 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5084 oper_method = res.ResolveOperator (rc, ref args);
5085 if (oper_method == null)
5088 MethodSpec best_original = null;
5089 foreach (MethodSpec ms in left_operators) {
5090 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5096 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5098 // Expression trees use lifted notation in this case
5100 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5101 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5104 var ptypes = best_original.Parameters.Types;
5106 if (left.IsNull || right.IsNull) {
5108 // The lifted operator produces a null value if one or both operands are null
5110 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5111 type = oper_method.ReturnType;
5112 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5116 // The lifted operator produces the value false if one or both operands are null for
5117 // relational operators.
5119 if ((oper & Operator.RelationalMask) != 0) {
5121 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5122 // because return type is actually bool
5124 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5127 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5128 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5132 type = oper_method.ReturnType;
5133 var lifted = new Nullable.LiftedBinaryOperator (this);
5134 lifted.UserOperator = best_original;
5136 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5137 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5140 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5141 lifted.UnwrapRight = new Nullable.Unwrap (right);
5144 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5145 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5147 return lifted.Resolve (rc);
5150 if ((oper & Operator.LogicalMask) != 0) {
5151 // TODO: CreateExpressionTree is allocated every time
5152 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5153 oper == Operator.LogicalAnd, loc).Resolve (rc);
5155 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5158 this.left = larg.Expr;
5159 this.right = rarg.Expr;
5164 bool IsLiftedOperatorApplicable ()
5166 if (left.Type.IsNullableType) {
5167 if ((oper & Operator.EqualityMask) != 0)
5168 return !right.IsNull;
5173 if (right.Type.IsNullableType) {
5174 if ((oper & Operator.EqualityMask) != 0)
5175 return !left.IsNull;
5180 if (TypeSpec.IsValueType (left.Type))
5181 return right.IsNull;
5183 if (TypeSpec.IsValueType (right.Type))
5189 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5191 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5192 if (nullable_type == null)
5196 // Lifted operators permit predefined and user-defined operators that operate
5197 // on non-nullable value types to also be used with nullable forms of those types.
5198 // Lifted operators are constructed from predefined and user-defined operators
5199 // that meet certain requirements
5201 List<MemberSpec> lifted = null;
5202 foreach (MethodSpec oper in operators) {
5204 if ((Oper & Operator.ComparisonMask) != 0) {
5206 // Result type must be of type bool for lifted comparison operators
5208 rt = oper.ReturnType;
5209 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5212 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5218 var ptypes = oper.Parameters.Types;
5219 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5223 // LAMESPEC: I am not sure why but for equality operators to be lifted
5224 // both types have to match
5226 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5230 lifted = new List<MemberSpec> ();
5233 // The lifted form is constructed by adding a single ? modifier to each operand and
5234 // result type except for comparison operators where return type is bool
5237 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5239 var parameters = ParametersCompiled.CreateFullyResolved (
5240 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5241 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5243 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5244 rt, parameters, oper.Modifiers);
5246 lifted.Add (lifted_op);
5253 // Merge two sets of user operators into one, they are mostly distinguish
5254 // except when they share base type and it contains an operator
5256 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5258 var combined = new List<MemberSpec> (left.Count + right.Count);
5259 combined.AddRange (left);
5260 foreach (var r in right) {
5262 foreach (var l in left) {
5263 if (l.DeclaringType == r.DeclaringType) {
5276 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5278 if (c is IntegralConstant || c is CharConstant) {
5280 c.ConvertExplicitly (true, type);
5281 } catch (OverflowException) {
5282 ec.Report.Warning (652, 2, loc,
5283 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5284 type.GetSignatureForError ());
5290 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5291 /// context of a conditional bool expression. This function will return
5292 /// false if it is was possible to use EmitBranchable, or true if it was.
5294 /// The expression's code is generated, and we will generate a branch to `target'
5295 /// if the resulting expression value is equal to isTrue
5297 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5299 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5300 left = left.EmitToField (ec);
5302 if ((oper & Operator.LogicalMask) == 0) {
5303 right = right.EmitToField (ec);
5308 // This is more complicated than it looks, but its just to avoid
5309 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5310 // but on top of that we want for == and != to use a special path
5311 // if we are comparing against null
5313 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5314 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5317 // put the constant on the rhs, for simplicity
5319 if (left is Constant) {
5320 Expression swap = right;
5326 // brtrue/brfalse works with native int only
5328 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5329 left.EmitBranchable (ec, target, my_on_true);
5332 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5333 // right is a boolean, and it's not 'false' => it is 'true'
5334 left.EmitBranchable (ec, target, !my_on_true);
5338 } else if (oper == Operator.LogicalAnd) {
5341 Label tests_end = ec.DefineLabel ();
5343 left.EmitBranchable (ec, tests_end, false);
5344 right.EmitBranchable (ec, target, true);
5345 ec.MarkLabel (tests_end);
5348 // This optimizes code like this
5349 // if (true && i > 4)
5351 if (!(left is Constant))
5352 left.EmitBranchable (ec, target, false);
5354 if (!(right is Constant))
5355 right.EmitBranchable (ec, target, false);
5360 } else if (oper == Operator.LogicalOr){
5362 left.EmitBranchable (ec, target, true);
5363 right.EmitBranchable (ec, target, true);
5366 Label tests_end = ec.DefineLabel ();
5367 left.EmitBranchable (ec, tests_end, true);
5368 right.EmitBranchable (ec, target, false);
5369 ec.MarkLabel (tests_end);
5374 } else if ((oper & Operator.ComparisonMask) == 0) {
5375 base.EmitBranchable (ec, target, on_true);
5382 TypeSpec t = left.Type;
5383 bool is_float = IsFloat (t);
5384 bool is_unsigned = is_float || IsUnsigned (t);
5387 case Operator.Equality:
5389 ec.Emit (OpCodes.Beq, target);
5391 ec.Emit (OpCodes.Bne_Un, target);
5394 case Operator.Inequality:
5396 ec.Emit (OpCodes.Bne_Un, target);
5398 ec.Emit (OpCodes.Beq, target);
5401 case Operator.LessThan:
5403 if (is_unsigned && !is_float)
5404 ec.Emit (OpCodes.Blt_Un, target);
5406 ec.Emit (OpCodes.Blt, target);
5409 ec.Emit (OpCodes.Bge_Un, target);
5411 ec.Emit (OpCodes.Bge, target);
5414 case Operator.GreaterThan:
5416 if (is_unsigned && !is_float)
5417 ec.Emit (OpCodes.Bgt_Un, target);
5419 ec.Emit (OpCodes.Bgt, target);
5422 ec.Emit (OpCodes.Ble_Un, target);
5424 ec.Emit (OpCodes.Ble, target);
5427 case Operator.LessThanOrEqual:
5429 if (is_unsigned && !is_float)
5430 ec.Emit (OpCodes.Ble_Un, target);
5432 ec.Emit (OpCodes.Ble, target);
5435 ec.Emit (OpCodes.Bgt_Un, target);
5437 ec.Emit (OpCodes.Bgt, target);
5441 case Operator.GreaterThanOrEqual:
5443 if (is_unsigned && !is_float)
5444 ec.Emit (OpCodes.Bge_Un, target);
5446 ec.Emit (OpCodes.Bge, target);
5449 ec.Emit (OpCodes.Blt_Un, target);
5451 ec.Emit (OpCodes.Blt, target);
5454 throw new InternalErrorException (oper.ToString ());
5458 public override void Emit (EmitContext ec)
5460 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5461 left = left.EmitToField (ec);
5463 if ((oper & Operator.LogicalMask) == 0) {
5464 right = right.EmitToField (ec);
5469 // Handle short-circuit operators differently
5472 if ((oper & Operator.LogicalMask) != 0) {
5473 Label load_result = ec.DefineLabel ();
5474 Label end = ec.DefineLabel ();
5476 bool is_or = oper == Operator.LogicalOr;
5477 left.EmitBranchable (ec, load_result, is_or);
5479 ec.Emit (OpCodes.Br_S, end);
5481 ec.MarkLabel (load_result);
5482 ec.EmitInt (is_or ? 1 : 0);
5488 // Optimize zero-based operations which cannot be optimized at expression level
5490 if (oper == Operator.Subtraction) {
5491 var lc = left as IntegralConstant;
5492 if (lc != null && lc.IsDefaultValue) {
5494 ec.Emit (OpCodes.Neg);
5499 EmitOperator (ec, left, right);
5502 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5507 EmitOperatorOpcode (ec, oper, left.Type, right);
5510 // Emit result enumerable conversion this way because it's quite complicated get it
5511 // to resolved tree because expression tree cannot see it.
5513 if (enum_conversion != 0)
5514 ConvCast.Emit (ec, enum_conversion);
5517 public override void EmitSideEffect (EmitContext ec)
5519 if ((oper & Operator.LogicalMask) != 0 ||
5520 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5521 base.EmitSideEffect (ec);
5523 left.EmitSideEffect (ec);
5524 right.EmitSideEffect (ec);
5528 public override Expression EmitToField (EmitContext ec)
5530 if ((oper & Operator.LogicalMask) == 0) {
5531 var await_expr = left as Await;
5532 if (await_expr != null && right.IsSideEffectFree) {
5533 await_expr.Statement.EmitPrologue (ec);
5534 left = await_expr.Statement.GetResultExpression (ec);
5538 await_expr = right as Await;
5539 if (await_expr != null && left.IsSideEffectFree) {
5540 await_expr.Statement.EmitPrologue (ec);
5541 right = await_expr.Statement.GetResultExpression (ec);
5546 return base.EmitToField (ec);
5549 protected override void CloneTo (CloneContext clonectx, Expression t)
5551 Binary target = (Binary) t;
5553 target.left = left.Clone (clonectx);
5554 target.right = right.Clone (clonectx);
5557 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5559 Arguments binder_args = new Arguments (4);
5561 MemberAccess sle = new MemberAccess (new MemberAccess (
5562 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5564 CSharpBinderFlags flags = 0;
5565 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5566 flags = CSharpBinderFlags.CheckedContext;
5568 if ((oper & Operator.LogicalMask) != 0)
5569 flags |= CSharpBinderFlags.BinaryOperationLogical;
5571 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5572 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5573 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5574 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5576 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5579 public override Expression CreateExpressionTree (ResolveContext ec)
5581 return CreateExpressionTree (ec, null);
5584 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5587 bool lift_arg = false;
5590 case Operator.Addition:
5591 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5592 method_name = "AddChecked";
5594 method_name = "Add";
5596 case Operator.BitwiseAnd:
5597 method_name = "And";
5599 case Operator.BitwiseOr:
5602 case Operator.Division:
5603 method_name = "Divide";
5605 case Operator.Equality:
5606 method_name = "Equal";
5609 case Operator.ExclusiveOr:
5610 method_name = "ExclusiveOr";
5612 case Operator.GreaterThan:
5613 method_name = "GreaterThan";
5616 case Operator.GreaterThanOrEqual:
5617 method_name = "GreaterThanOrEqual";
5620 case Operator.Inequality:
5621 method_name = "NotEqual";
5624 case Operator.LeftShift:
5625 method_name = "LeftShift";
5627 case Operator.LessThan:
5628 method_name = "LessThan";
5631 case Operator.LessThanOrEqual:
5632 method_name = "LessThanOrEqual";
5635 case Operator.LogicalAnd:
5636 method_name = "AndAlso";
5638 case Operator.LogicalOr:
5639 method_name = "OrElse";
5641 case Operator.Modulus:
5642 method_name = "Modulo";
5644 case Operator.Multiply:
5645 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5646 method_name = "MultiplyChecked";
5648 method_name = "Multiply";
5650 case Operator.RightShift:
5651 method_name = "RightShift";
5653 case Operator.Subtraction:
5654 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5655 method_name = "SubtractChecked";
5657 method_name = "Subtract";
5661 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5664 Arguments args = new Arguments (2);
5665 args.Add (new Argument (left.CreateExpressionTree (ec)));
5666 args.Add (new Argument (right.CreateExpressionTree (ec)));
5667 if (method != null) {
5669 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5671 args.Add (new Argument (method));
5674 return CreateExpressionFactoryCall (ec, method_name, args);
5677 public override object Accept (StructuralVisitor visitor)
5679 return visitor.Visit (this);
5685 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5686 // b, c, d... may be strings or objects.
5688 public class StringConcat : Expression
5690 Arguments arguments;
5692 StringConcat (Location loc)
5695 arguments = new Arguments (2);
5698 public override bool ContainsEmitWithAwait ()
5700 return arguments.ContainsEmitWithAwait ();
5703 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5705 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5706 throw new ArgumentException ();
5708 var s = new StringConcat (loc);
5709 s.type = rc.BuiltinTypes.String;
5710 s.eclass = ExprClass.Value;
5712 s.Append (rc, left);
5713 s.Append (rc, right);
5717 public override Expression CreateExpressionTree (ResolveContext ec)
5719 Argument arg = arguments [0];
5720 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5724 // Creates nested calls tree from an array of arguments used for IL emit
5726 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5728 Arguments concat_args = new Arguments (2);
5729 Arguments add_args = new Arguments (3);
5731 concat_args.Add (left);
5732 add_args.Add (new Argument (left_etree));
5734 concat_args.Add (arguments [pos]);
5735 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5737 var methods = GetConcatMethodCandidates ();
5738 if (methods == null)
5741 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5742 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5746 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5748 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5749 if (++pos == arguments.Count)
5752 left = new Argument (new EmptyExpression (method.ReturnType));
5753 return CreateExpressionAddCall (ec, left, expr, pos);
5756 protected override Expression DoResolve (ResolveContext ec)
5761 void Append (ResolveContext rc, Expression operand)
5766 StringConstant sc = operand as StringConstant;
5768 if (arguments.Count != 0) {
5769 Argument last_argument = arguments [arguments.Count - 1];
5770 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5771 if (last_expr_constant != null) {
5772 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5778 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5780 StringConcat concat_oper = operand as StringConcat;
5781 if (concat_oper != null) {
5782 arguments.AddRange (concat_oper.arguments);
5787 arguments.Add (new Argument (operand));
5790 IList<MemberSpec> GetConcatMethodCandidates ()
5792 return MemberCache.FindMembers (type, "Concat", true);
5795 public override void Emit (EmitContext ec)
5797 // Optimize by removing any extra null arguments, they are no-op
5798 for (int i = 0; i < arguments.Count; ++i) {
5799 if (arguments[i].Expr is NullConstant)
5800 arguments.RemoveAt (i--);
5803 var members = GetConcatMethodCandidates ();
5804 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5805 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5806 if (method != null) {
5807 var call = new CallEmitter ();
5808 call.EmitPredefined (ec, method, arguments, false);
5812 public override void FlowAnalysis (FlowAnalysisContext fc)
5814 arguments.FlowAnalysis (fc);
5817 public override SLE.Expression MakeExpression (BuilderContext ctx)
5819 if (arguments.Count != 2)
5820 throw new NotImplementedException ("arguments.Count != 2");
5822 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5823 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5828 // User-defined conditional logical operator
5830 public class ConditionalLogicalOperator : UserOperatorCall
5832 readonly bool is_and;
5833 Expression oper_expr;
5835 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5836 : base (oper, arguments, expr_tree, loc)
5838 this.is_and = is_and;
5839 eclass = ExprClass.Unresolved;
5842 protected override Expression DoResolve (ResolveContext ec)
5844 AParametersCollection pd = oper.Parameters;
5845 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5846 ec.Report.Error (217, loc,
5847 "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",
5848 oper.GetSignatureForError ());
5852 Expression left_dup = new EmptyExpression (type);
5853 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5854 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5855 if (op_true == null || op_false == null) {
5856 ec.Report.Error (218, loc,
5857 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5858 type.GetSignatureForError (), oper.GetSignatureForError ());
5862 oper_expr = is_and ? op_false : op_true;
5863 eclass = ExprClass.Value;
5867 public override void Emit (EmitContext ec)
5869 Label end_target = ec.DefineLabel ();
5872 // Emit and duplicate left argument
5874 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5875 if (right_contains_await) {
5876 arguments[0] = arguments[0].EmitToField (ec, false);
5877 arguments[0].Expr.Emit (ec);
5879 arguments[0].Expr.Emit (ec);
5880 ec.Emit (OpCodes.Dup);
5881 arguments.RemoveAt (0);
5884 oper_expr.EmitBranchable (ec, end_target, true);
5888 if (right_contains_await) {
5890 // Special handling when right expression contains await and left argument
5891 // could not be left on stack before logical branch
5893 Label skip_left_load = ec.DefineLabel ();
5894 ec.Emit (OpCodes.Br_S, skip_left_load);
5895 ec.MarkLabel (end_target);
5896 arguments[0].Expr.Emit (ec);
5897 ec.MarkLabel (skip_left_load);
5899 ec.MarkLabel (end_target);
5904 public class PointerArithmetic : Expression {
5905 Expression left, right;
5906 readonly Binary.Operator op;
5909 // We assume that `l' is always a pointer
5911 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5920 public override bool ContainsEmitWithAwait ()
5922 throw new NotImplementedException ();
5925 public override Expression CreateExpressionTree (ResolveContext ec)
5927 Error_PointerInsideExpressionTree (ec);
5931 protected override Expression DoResolve (ResolveContext ec)
5933 eclass = ExprClass.Variable;
5935 var pc = left.Type as PointerContainer;
5936 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5937 Error_VoidPointerOperation (ec);
5944 public override void Emit (EmitContext ec)
5946 TypeSpec op_type = left.Type;
5948 // It must be either array or fixed buffer
5950 if (TypeManager.HasElementType (op_type)) {
5951 element = TypeManager.GetElementType (op_type);
5953 FieldExpr fe = left as FieldExpr;
5955 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5960 int size = BuiltinTypeSpec.GetSize(element);
5961 TypeSpec rtype = right.Type;
5963 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5965 // handle (pointer - pointer)
5969 ec.Emit (OpCodes.Sub);
5973 ec.Emit (OpCodes.Sizeof, element);
5976 ec.Emit (OpCodes.Div);
5978 ec.Emit (OpCodes.Conv_I8);
5981 // handle + and - on (pointer op int)
5983 Constant left_const = left as Constant;
5984 if (left_const != null) {
5986 // Optimize ((T*)null) pointer operations
5988 if (left_const.IsDefaultValue) {
5989 left = EmptyExpression.Null;
5997 var right_const = right as Constant;
5998 if (right_const != null) {
6000 // Optimize 0-based arithmetic
6002 if (right_const.IsDefaultValue)
6006 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6008 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6010 // TODO: Should be the checks resolve context sensitive?
6011 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6012 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6018 if (right_const == null) {
6019 switch (rtype.BuiltinType) {
6020 case BuiltinTypeSpec.Type.SByte:
6021 case BuiltinTypeSpec.Type.Byte:
6022 case BuiltinTypeSpec.Type.Short:
6023 case BuiltinTypeSpec.Type.UShort:
6024 case BuiltinTypeSpec.Type.Int:
6025 ec.Emit (OpCodes.Conv_I);
6027 case BuiltinTypeSpec.Type.UInt:
6028 ec.Emit (OpCodes.Conv_U);
6033 if (right_const == null && size != 1){
6035 ec.Emit (OpCodes.Sizeof, element);
6038 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6039 ec.Emit (OpCodes.Conv_I8);
6041 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6044 if (left_const == null) {
6045 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6046 ec.Emit (OpCodes.Conv_I);
6047 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6048 ec.Emit (OpCodes.Conv_U);
6050 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6057 // A boolean-expression is an expression that yields a result
6060 public class BooleanExpression : ShimExpression
6062 public BooleanExpression (Expression expr)
6065 this.loc = expr.Location;
6068 public override Expression CreateExpressionTree (ResolveContext ec)
6070 // TODO: We should emit IsTrue (v4) instead of direct user operator
6071 // call but that would break csc compatibility
6072 return base.CreateExpressionTree (ec);
6075 protected override Expression DoResolve (ResolveContext ec)
6077 // A boolean-expression is required to be of a type
6078 // that can be implicitly converted to bool or of
6079 // a type that implements operator true
6081 expr = expr.Resolve (ec);
6085 Assign ass = expr as Assign;
6086 if (ass != null && ass.Source is Constant) {
6087 ec.Report.Warning (665, 3, loc,
6088 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6091 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6094 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6095 Arguments args = new Arguments (1);
6096 args.Add (new Argument (expr));
6097 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6100 type = ec.BuiltinTypes.Bool;
6101 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6102 if (converted != null)
6106 // If no implicit conversion to bool exists, try using `operator true'
6108 converted = GetOperatorTrue (ec, expr, loc);
6109 if (converted == null) {
6110 expr.Error_ValueCannotBeConverted (ec, type, false);
6117 public override object Accept (StructuralVisitor visitor)
6119 return visitor.Visit (this);
6123 public class BooleanExpressionFalse : Unary
6125 public BooleanExpressionFalse (Expression expr)
6126 : base (Operator.LogicalNot, expr, expr.Location)
6130 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6132 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6137 /// Implements the ternary conditional operator (?:)
6139 public class Conditional : Expression {
6140 Expression expr, true_expr, false_expr;
6142 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6145 this.true_expr = true_expr;
6146 this.false_expr = false_expr;
6152 public Expression Expr {
6158 public Expression TrueExpr {
6164 public Expression FalseExpr {
6172 public override bool ContainsEmitWithAwait ()
6174 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6177 public override Expression CreateExpressionTree (ResolveContext ec)
6179 Arguments args = new Arguments (3);
6180 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6181 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6182 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6183 return CreateExpressionFactoryCall (ec, "Condition", args);
6186 protected override Expression DoResolve (ResolveContext ec)
6188 expr = expr.Resolve (ec);
6189 true_expr = true_expr.Resolve (ec);
6190 false_expr = false_expr.Resolve (ec);
6192 if (true_expr == null || false_expr == null || expr == null)
6195 eclass = ExprClass.Value;
6196 TypeSpec true_type = true_expr.Type;
6197 TypeSpec false_type = false_expr.Type;
6201 // First, if an implicit conversion exists from true_expr
6202 // to false_expr, then the result type is of type false_expr.Type
6204 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6205 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6206 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6208 // Check if both can convert implicitly to each other's type
6212 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6213 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6215 // LAMESPEC: There seems to be hardcoded promotition to int type when
6216 // both sides are numeric constants and one side is int constant and
6217 // other side is numeric constant convertible to int.
6219 // var res = condition ? (short)1 : 1;
6221 // Type of res is int even if according to the spec the conversion is
6222 // ambiguous because 1 literal can be converted to short.
6224 if (conv_false_expr != null) {
6225 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6227 conv_false_expr = null;
6228 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6229 conv_false_expr = null;
6233 if (conv_false_expr != null) {
6234 ec.Report.Error (172, true_expr.Location,
6235 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6236 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6241 if (true_expr.Type != type)
6242 true_expr = EmptyCast.Create (true_expr, type);
6243 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6246 if (false_type != InternalType.ErrorType) {
6247 ec.Report.Error (173, true_expr.Location,
6248 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6249 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6255 Constant c = expr as Constant;
6257 bool is_false = c.IsDefaultValue;
6260 // Don't issue the warning for constant expressions
6262 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6263 // CSC: Missing warning
6264 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6267 return ReducedExpression.Create (
6268 is_false ? false_expr : true_expr, this,
6269 false_expr is Constant && true_expr is Constant).Resolve (ec);
6275 public override void Emit (EmitContext ec)
6277 Label false_target = ec.DefineLabel ();
6278 Label end_target = ec.DefineLabel ();
6280 expr.EmitBranchable (ec, false_target, false);
6281 true_expr.Emit (ec);
6284 // Verifier doesn't support interface merging. When there are two types on
6285 // the stack without common type hint and the common type is an interface.
6286 // Use temporary local to give verifier hint on what type to unify the stack
6288 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6289 var temp = ec.GetTemporaryLocal (type);
6290 ec.Emit (OpCodes.Stloc, temp);
6291 ec.Emit (OpCodes.Ldloc, temp);
6292 ec.FreeTemporaryLocal (temp, type);
6295 ec.Emit (OpCodes.Br, end_target);
6296 ec.MarkLabel (false_target);
6297 false_expr.Emit (ec);
6298 ec.MarkLabel (end_target);
6301 public override void FlowAnalysis (FlowAnalysisContext fc)
6303 expr.FlowAnalysisConditional (fc);
6304 var expr_true = fc.DefiniteAssignmentOnTrue;
6305 var expr_false = fc.DefiniteAssignmentOnFalse;
6307 fc.BranchDefiniteAssignment (expr_true);
6308 true_expr.FlowAnalysis (fc);
6309 var true_fc = fc.DefiniteAssignment;
6311 fc.BranchDefiniteAssignment (expr_false);
6312 false_expr.FlowAnalysis (fc);
6314 fc.DefiniteAssignment &= true_fc;
6317 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6319 expr.FlowAnalysisConditional (fc);
6320 var expr_true = fc.DefiniteAssignmentOnTrue;
6321 var expr_false = fc.DefiniteAssignmentOnFalse;
6323 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6324 true_expr.FlowAnalysisConditional (fc);
6325 var true_fc = fc.DefiniteAssignment;
6326 var true_da_true = fc.DefiniteAssignmentOnTrue;
6327 var true_da_false = fc.DefiniteAssignmentOnFalse;
6329 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6330 false_expr.FlowAnalysisConditional (fc);
6332 fc.DefiniteAssignment &= true_fc;
6333 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6334 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6337 protected override void CloneTo (CloneContext clonectx, Expression t)
6339 Conditional target = (Conditional) t;
6341 target.expr = expr.Clone (clonectx);
6342 target.true_expr = true_expr.Clone (clonectx);
6343 target.false_expr = false_expr.Clone (clonectx);
6347 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6349 LocalTemporary temp;
6352 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6353 public abstract void SetHasAddressTaken ();
6355 public abstract bool IsLockedByStatement { get; set; }
6357 public abstract bool IsFixed { get; }
6358 public abstract bool IsRef { get; }
6359 public abstract string Name { get; }
6362 // Variable IL data, it has to be protected to encapsulate hoisted variables
6364 protected abstract ILocalVariable Variable { get; }
6367 // Variable flow-analysis data
6369 public abstract VariableInfo VariableInfo { get; }
6372 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6374 HoistedVariable hv = GetHoistedVariable (ec);
6376 hv.AddressOf (ec, mode);
6380 Variable.EmitAddressOf (ec);
6383 public override bool ContainsEmitWithAwait ()
6388 public override Expression CreateExpressionTree (ResolveContext ec)
6390 HoistedVariable hv = GetHoistedVariable (ec);
6392 return hv.CreateExpressionTree ();
6394 Arguments arg = new Arguments (1);
6395 arg.Add (new Argument (this));
6396 return CreateExpressionFactoryCall (ec, "Constant", arg);
6399 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6401 if (IsLockedByStatement) {
6402 rc.Report.Warning (728, 2, loc,
6403 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6410 public override void Emit (EmitContext ec)
6415 public override void EmitSideEffect (EmitContext ec)
6421 // This method is used by parameters that are references, that are
6422 // being passed as references: we only want to pass the pointer (that
6423 // is already stored in the parameter, not the address of the pointer,
6424 // and not the value of the variable).
6426 public void EmitLoad (EmitContext ec)
6431 public void Emit (EmitContext ec, bool leave_copy)
6433 HoistedVariable hv = GetHoistedVariable (ec);
6435 hv.Emit (ec, leave_copy);
6443 // If we are a reference, we loaded on the stack a pointer
6444 // Now lets load the real value
6446 ec.EmitLoadFromPtr (type);
6450 ec.Emit (OpCodes.Dup);
6453 temp = new LocalTemporary (Type);
6459 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6460 bool prepare_for_load)
6462 HoistedVariable hv = GetHoistedVariable (ec);
6464 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6468 New n_source = source as New;
6469 if (n_source != null) {
6470 if (!n_source.Emit (ec, this)) {
6474 ec.EmitLoadFromPtr (type);
6486 ec.Emit (OpCodes.Dup);
6488 temp = new LocalTemporary (Type);
6494 ec.EmitStoreFromPtr (type);
6496 Variable.EmitAssign (ec);
6504 public override Expression EmitToField (EmitContext ec)
6506 HoistedVariable hv = GetHoistedVariable (ec);
6508 return hv.EmitToField (ec);
6511 return base.EmitToField (ec);
6514 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6516 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6519 public HoistedVariable GetHoistedVariable (EmitContext ec)
6521 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6524 public override string GetSignatureForError ()
6529 public bool IsHoisted {
6530 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6535 // Resolved reference to a local variable
6537 public class LocalVariableReference : VariableReference
6539 public LocalVariable local_info;
6541 public LocalVariableReference (LocalVariable li, Location l)
6543 this.local_info = li;
6547 public override VariableInfo VariableInfo {
6548 get { return local_info.VariableInfo; }
6551 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6553 return local_info.HoistedVariant;
6559 // A local variable is always fixed
6561 public override bool IsFixed {
6567 public override bool IsLockedByStatement {
6569 return local_info.IsLocked;
6572 local_info.IsLocked = value;
6576 public override bool IsRef {
6577 get { return false; }
6580 public override string Name {
6581 get { return local_info.Name; }
6586 public override void FlowAnalysis (FlowAnalysisContext fc)
6588 VariableInfo variable_info = VariableInfo;
6589 if (variable_info == null)
6592 if (fc.IsDefinitelyAssigned (variable_info))
6595 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6596 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6599 public override void SetHasAddressTaken ()
6601 local_info.SetHasAddressTaken ();
6604 void DoResolveBase (ResolveContext ec)
6606 eclass = ExprClass.Variable;
6607 type = local_info.Type;
6610 // If we are referencing a variable from the external block
6611 // flag it for capturing
6613 if (ec.MustCaptureVariable (local_info)) {
6614 if (local_info.AddressTaken) {
6615 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6616 } else if (local_info.IsFixed) {
6617 ec.Report.Error (1764, loc,
6618 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6619 GetSignatureForError ());
6622 if (ec.IsVariableCapturingRequired) {
6623 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6624 storey.CaptureLocalVariable (ec, local_info);
6629 protected override Expression DoResolve (ResolveContext ec)
6631 local_info.SetIsUsed ();
6635 if (local_info.Type == InternalType.VarOutType) {
6636 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6637 GetSignatureForError ());
6639 type = InternalType.ErrorType;
6645 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6648 // Don't be too pedantic when variable is used as out param or for some broken code
6649 // which uses property/indexer access to run some initialization
6651 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6652 local_info.SetIsUsed ();
6654 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6655 if (rhs == EmptyExpression.LValueMemberAccess) {
6656 // CS1654 already reported
6660 if (rhs == EmptyExpression.OutAccess) {
6661 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6662 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6663 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6664 } else if (rhs == EmptyExpression.UnaryAddress) {
6665 code = 459; msg = "Cannot take the address of {1} `{0}'";
6667 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6669 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6673 if (eclass == ExprClass.Unresolved)
6676 return base.DoResolveLValue (ec, rhs);
6679 public override int GetHashCode ()
6681 return local_info.GetHashCode ();
6684 public override bool Equals (object obj)
6686 LocalVariableReference lvr = obj as LocalVariableReference;
6690 return local_info == lvr.local_info;
6693 protected override ILocalVariable Variable {
6694 get { return local_info; }
6697 public override string ToString ()
6699 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6702 protected override void CloneTo (CloneContext clonectx, Expression t)
6709 /// This represents a reference to a parameter in the intermediate
6712 public class ParameterReference : VariableReference
6714 protected ParametersBlock.ParameterInfo pi;
6716 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6724 public override bool IsLockedByStatement {
6729 pi.IsLocked = value;
6733 public override bool IsRef {
6734 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6737 bool HasOutModifier {
6738 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6741 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6743 return pi.Parameter.HoistedVariant;
6747 // A ref or out parameter is classified as a moveable variable, even
6748 // if the argument given for the parameter is a fixed variable
6750 public override bool IsFixed {
6751 get { return !IsRef; }
6754 public override string Name {
6755 get { return Parameter.Name; }
6758 public Parameter Parameter {
6759 get { return pi.Parameter; }
6762 public override VariableInfo VariableInfo {
6763 get { return pi.VariableInfo; }
6766 protected override ILocalVariable Variable {
6767 get { return Parameter; }
6772 public override void AddressOf (EmitContext ec, AddressOp mode)
6775 // ParameterReferences might already be a reference
6782 base.AddressOf (ec, mode);
6785 public override void SetHasAddressTaken ()
6787 Parameter.HasAddressTaken = true;
6790 bool DoResolveBase (ResolveContext ec)
6792 if (eclass != ExprClass.Unresolved)
6795 type = pi.ParameterType;
6796 eclass = ExprClass.Variable;
6799 // If we are referencing a parameter from the external block
6800 // flag it for capturing
6802 if (ec.MustCaptureVariable (pi)) {
6803 if (Parameter.HasAddressTaken)
6804 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6807 ec.Report.Error (1628, loc,
6808 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6809 Name, ec.CurrentAnonymousMethod.ContainerType);
6812 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6813 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6814 storey.CaptureParameter (ec, pi, this);
6821 public override int GetHashCode ()
6823 return Name.GetHashCode ();
6826 public override bool Equals (object obj)
6828 ParameterReference pr = obj as ParameterReference;
6832 return Name == pr.Name;
6835 protected override void CloneTo (CloneContext clonectx, Expression target)
6841 public override Expression CreateExpressionTree (ResolveContext ec)
6843 HoistedVariable hv = GetHoistedVariable (ec);
6845 return hv.CreateExpressionTree ();
6847 return Parameter.ExpressionTreeVariableReference ();
6850 protected override Expression DoResolve (ResolveContext ec)
6852 if (!DoResolveBase (ec))
6858 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6860 if (!DoResolveBase (ec))
6863 if (Parameter.HoistedVariant != null)
6864 Parameter.HoistedVariant.IsAssigned = true;
6866 return base.DoResolveLValue (ec, right_side);
6869 public override void FlowAnalysis (FlowAnalysisContext fc)
6871 VariableInfo variable_info = VariableInfo;
6872 if (variable_info == null)
6875 if (fc.IsDefinitelyAssigned (variable_info))
6878 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6879 fc.SetVariableAssigned (variable_info);
6884 /// Invocation of methods or delegates.
6886 public class Invocation : ExpressionStatement
6888 public class Predefined : Invocation
6890 public Predefined (MethodGroupExpr expr, Arguments arguments)
6891 : base (expr, arguments)
6896 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6898 mg.BestCandidate.CheckObsoleteness (rc, loc);
6904 protected Arguments arguments;
6905 protected Expression expr;
6906 protected MethodGroupExpr mg;
6907 bool conditional_access_receiver;
6909 public Invocation (Expression expr, Arguments arguments)
6912 this.arguments = arguments;
6914 loc = expr.Location;
6919 public Arguments Arguments {
6925 public Expression Exp {
6931 public MethodGroupExpr MethodGroup {
6937 public override Location StartLocation {
6939 return expr.StartLocation;
6945 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6947 if (MethodGroup == null)
6950 var candidate = MethodGroup.BestCandidate;
6951 if (candidate == null || !(candidate.IsStatic || Exp is This))
6954 var args_count = arguments == null ? 0 : arguments.Count;
6955 if (args_count != body.Parameters.Count)
6958 var lambda_parameters = body.Block.Parameters.FixedParameters;
6959 for (int i = 0; i < args_count; ++i) {
6960 var pr = arguments[i].Expr as ParameterReference;
6964 if (lambda_parameters[i] != pr.Parameter)
6967 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6971 var emg = MethodGroup as ExtensionMethodGroupExpr;
6973 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6974 if (candidate.IsGeneric) {
6975 var targs = new TypeExpression [candidate.Arity];
6976 for (int i = 0; i < targs.Length; ++i) {
6977 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6980 mg.SetTypeArguments (null, new TypeArguments (targs));
6989 protected override void CloneTo (CloneContext clonectx, Expression t)
6991 Invocation target = (Invocation) t;
6993 if (arguments != null)
6994 target.arguments = arguments.Clone (clonectx);
6996 target.expr = expr.Clone (clonectx);
6999 public override bool ContainsEmitWithAwait ()
7001 if (arguments != null && arguments.ContainsEmitWithAwait ())
7004 return mg.ContainsEmitWithAwait ();
7007 public override Expression CreateExpressionTree (ResolveContext ec)
7009 Expression instance = mg.IsInstance ?
7010 mg.InstanceExpression.CreateExpressionTree (ec) :
7011 new NullLiteral (loc);
7013 var args = Arguments.CreateForExpressionTree (ec, arguments,
7015 mg.CreateExpressionTree (ec));
7017 return CreateExpressionFactoryCall (ec, "Call", args);
7020 void ResolveConditionalAccessReceiver (ResolveContext rc)
7022 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7023 conditional_access_receiver = true;
7027 protected override Expression DoResolve (ResolveContext rc)
7029 ResolveConditionalAccessReceiver (rc);
7030 return DoResolveInvocation (rc);
7033 Expression DoResolveInvocation (ResolveContext ec)
7035 Expression member_expr;
7036 var atn = expr as ATypeNameExpression;
7038 var flags = default (ResolveContext.FlagsHandle);
7039 if (conditional_access_receiver)
7040 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7043 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7044 if (member_expr != null) {
7045 var name_of = member_expr as NameOf;
7046 if (name_of != null) {
7047 return name_of.ResolveOverload (ec, arguments);
7050 member_expr = member_expr.Resolve (ec);
7053 member_expr = expr.Resolve (ec);
7056 if (conditional_access_receiver)
7059 if (member_expr == null)
7063 // Next, evaluate all the expressions in the argument list
7065 bool dynamic_arg = false;
7066 if (arguments != null) {
7067 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7068 arguments.Resolve (ec, out dynamic_arg);
7072 TypeSpec expr_type = member_expr.Type;
7073 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7074 return DoResolveDynamic (ec, member_expr);
7076 mg = member_expr as MethodGroupExpr;
7077 Expression invoke = null;
7080 if (expr_type != null && expr_type.IsDelegate) {
7081 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7082 invoke = invoke.Resolve (ec);
7083 if (invoke == null || !dynamic_arg)
7086 if (member_expr is RuntimeValueExpression) {
7087 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7088 member_expr.Type.GetSignatureForError ());
7092 MemberExpr me = member_expr as MemberExpr;
7094 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7098 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7099 member_expr.GetSignatureForError ());
7104 if (invoke == null) {
7105 mg = DoResolveOverload (ec);
7111 return DoResolveDynamic (ec, member_expr);
7113 var method = mg.BestCandidate;
7114 type = mg.BestCandidateReturnType;
7115 if (conditional_access_receiver)
7116 type = LiftMemberType (ec, type);
7118 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7120 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7122 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7126 IsSpecialMethodInvocation (ec, method, loc);
7128 eclass = ExprClass.Value;
7132 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7135 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7137 args = dmb.Arguments;
7138 if (arguments != null)
7139 args.AddRange (arguments);
7140 } else if (mg == null) {
7141 if (arguments == null)
7142 args = new Arguments (1);
7146 args.Insert (0, new Argument (memberExpr));
7150 ec.Report.Error (1971, loc,
7151 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7156 if (arguments == null)
7157 args = new Arguments (1);
7161 MemberAccess ma = expr as MemberAccess;
7163 var inst = mg.InstanceExpression;
7164 var left_type = inst as TypeExpr;
7165 if (left_type != null) {
7166 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7167 } else if (inst != null) {
7169 // Any value type has to be pass as by-ref to get back the same
7170 // instance on which the member was called
7172 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7173 Argument.AType.Ref : Argument.AType.None;
7174 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7176 } else { // is SimpleName
7178 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7180 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7185 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7188 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7190 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7193 public override void FlowAnalysis (FlowAnalysisContext fc)
7195 if (mg.IsConditionallyExcluded)
7198 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7200 mg.FlowAnalysis (fc);
7202 if (arguments != null)
7203 arguments.FlowAnalysis (fc);
7205 if (conditional_access_receiver)
7206 fc.DefiniteAssignment = da;
7209 public override string GetSignatureForError ()
7211 return mg.GetSignatureForError ();
7214 public override bool HasConditionalAccess ()
7216 return expr.HasConditionalAccess ();
7220 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7221 // or the type dynamic, then the member is invocable
7223 public static bool IsMemberInvocable (MemberSpec member)
7225 switch (member.Kind) {
7226 case MemberKind.Event:
7228 case MemberKind.Field:
7229 case MemberKind.Property:
7230 var m = member as IInterfaceMemberSpec;
7231 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7237 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7239 if (!method.IsReservedMethod)
7242 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7245 ec.Report.SymbolRelatedToPreviousError (method);
7246 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7247 method.GetSignatureForError ());
7252 public override void Emit (EmitContext ec)
7254 if (mg.IsConditionallyExcluded)
7257 if (conditional_access_receiver)
7258 mg.EmitCall (ec, arguments, type, false);
7260 mg.EmitCall (ec, arguments, false);
7263 public override void EmitStatement (EmitContext ec)
7265 if (mg.IsConditionallyExcluded)
7268 if (conditional_access_receiver)
7269 mg.EmitCall (ec, arguments, type, true);
7271 mg.EmitCall (ec, arguments, true);
7274 public override SLE.Expression MakeExpression (BuilderContext ctx)
7276 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7279 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7282 throw new NotSupportedException ();
7284 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7285 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7289 public override object Accept (StructuralVisitor visitor)
7291 return visitor.Visit (this);
7296 // Implements simple new expression
7298 public class New : ExpressionStatement, IMemoryLocation
7300 protected Arguments arguments;
7303 // During bootstrap, it contains the RequestedType,
7304 // but if `type' is not null, it *might* contain a NewDelegate
7305 // (because of field multi-initialization)
7307 protected Expression RequestedType;
7309 protected MethodSpec method;
7311 public New (Expression requested_type, Arguments arguments, Location l)
7313 RequestedType = requested_type;
7314 this.arguments = arguments;
7319 public Arguments Arguments {
7326 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7328 public bool IsGeneratedStructConstructor {
7330 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7334 public Expression TypeExpression {
7336 return RequestedType;
7343 /// Converts complex core type syntax like 'new int ()' to simple constant
7345 public static Constant Constantify (TypeSpec t, Location loc)
7347 switch (t.BuiltinType) {
7348 case BuiltinTypeSpec.Type.Int:
7349 return new IntConstant (t, 0, loc);
7350 case BuiltinTypeSpec.Type.UInt:
7351 return new UIntConstant (t, 0, loc);
7352 case BuiltinTypeSpec.Type.Long:
7353 return new LongConstant (t, 0, loc);
7354 case BuiltinTypeSpec.Type.ULong:
7355 return new ULongConstant (t, 0, loc);
7356 case BuiltinTypeSpec.Type.Float:
7357 return new FloatConstant (t, 0, loc);
7358 case BuiltinTypeSpec.Type.Double:
7359 return new DoubleConstant (t, 0, loc);
7360 case BuiltinTypeSpec.Type.Short:
7361 return new ShortConstant (t, 0, loc);
7362 case BuiltinTypeSpec.Type.UShort:
7363 return new UShortConstant (t, 0, loc);
7364 case BuiltinTypeSpec.Type.SByte:
7365 return new SByteConstant (t, 0, loc);
7366 case BuiltinTypeSpec.Type.Byte:
7367 return new ByteConstant (t, 0, loc);
7368 case BuiltinTypeSpec.Type.Char:
7369 return new CharConstant (t, '\0', loc);
7370 case BuiltinTypeSpec.Type.Bool:
7371 return new BoolConstant (t, false, loc);
7372 case BuiltinTypeSpec.Type.Decimal:
7373 return new DecimalConstant (t, 0, loc);
7377 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7379 if (t.IsNullableType)
7380 return Nullable.LiftedNull.Create (t, loc);
7385 public override bool ContainsEmitWithAwait ()
7387 return arguments != null && arguments.ContainsEmitWithAwait ();
7391 // Checks whether the type is an interface that has the
7392 // [ComImport, CoClass] attributes and must be treated
7395 public Expression CheckComImport (ResolveContext ec)
7397 if (!type.IsInterface)
7401 // Turn the call into:
7402 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7404 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7405 if (real_class == null)
7408 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7409 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7410 return cast.Resolve (ec);
7413 public override Expression CreateExpressionTree (ResolveContext ec)
7416 if (method == null) {
7417 args = new Arguments (1);
7418 args.Add (new Argument (new TypeOf (type, loc)));
7420 args = Arguments.CreateForExpressionTree (ec,
7421 arguments, new TypeOfMethod (method, loc));
7424 return CreateExpressionFactoryCall (ec, "New", args);
7427 protected override Expression DoResolve (ResolveContext ec)
7429 type = RequestedType.ResolveAsType (ec);
7433 eclass = ExprClass.Value;
7435 if (type.IsPointer) {
7436 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7437 type.GetSignatureForError ());
7441 if (arguments == null) {
7442 Constant c = Constantify (type, RequestedType.Location);
7444 return ReducedExpression.Create (c, this);
7447 if (type.IsDelegate) {
7448 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7451 var tparam = type as TypeParameterSpec;
7452 if (tparam != null) {
7454 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7455 // where type parameter constraint is inflated to struct
7457 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7458 ec.Report.Error (304, loc,
7459 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7460 type.GetSignatureForError ());
7463 if ((arguments != null) && (arguments.Count != 0)) {
7464 ec.Report.Error (417, loc,
7465 "`{0}': cannot provide arguments when creating an instance of a variable type",
7466 type.GetSignatureForError ());
7472 if (type.IsStatic) {
7473 ec.Report.SymbolRelatedToPreviousError (type);
7474 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7478 if (type.IsInterface || type.IsAbstract){
7479 if (!TypeManager.IsGenericType (type)) {
7480 RequestedType = CheckComImport (ec);
7481 if (RequestedType != null)
7482 return RequestedType;
7485 ec.Report.SymbolRelatedToPreviousError (type);
7486 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7491 if (arguments != null) {
7492 arguments.Resolve (ec, out dynamic);
7497 method = ConstructorLookup (ec, type, ref arguments, loc);
7500 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7501 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7507 void DoEmitTypeParameter (EmitContext ec)
7509 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7513 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7514 ec.Emit (OpCodes.Call, ctor_factory);
7518 // This Emit can be invoked in two contexts:
7519 // * As a mechanism that will leave a value on the stack (new object)
7520 // * As one that wont (init struct)
7522 // If we are dealing with a ValueType, we have a few
7523 // situations to deal with:
7525 // * The target is a ValueType, and we have been provided
7526 // the instance (this is easy, we are being assigned).
7528 // * The target of New is being passed as an argument,
7529 // to a boxing operation or a function that takes a
7532 // In this case, we need to create a temporary variable
7533 // that is the argument of New.
7535 // Returns whether a value is left on the stack
7537 // *** Implementation note ***
7539 // To benefit from this optimization, each assignable expression
7540 // has to manually cast to New and call this Emit.
7542 // TODO: It's worth to implement it for arrays and fields
7544 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7546 bool is_value_type = type.IsStructOrEnum;
7547 VariableReference vr = target as VariableReference;
7549 if (target != null && is_value_type && (vr != null || method == null)) {
7550 target.AddressOf (ec, AddressOp.Store);
7551 } else if (vr != null && vr.IsRef) {
7555 if (arguments != null) {
7556 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7557 arguments = arguments.Emit (ec, false, true);
7559 arguments.Emit (ec);
7562 if (is_value_type) {
7563 if (method == null) {
7564 ec.Emit (OpCodes.Initobj, type);
7569 ec.MarkCallEntry (loc);
7570 ec.Emit (OpCodes.Call, method);
7575 if (type is TypeParameterSpec) {
7576 DoEmitTypeParameter (ec);
7580 ec.MarkCallEntry (loc);
7581 ec.Emit (OpCodes.Newobj, method);
7585 public override void Emit (EmitContext ec)
7587 LocalTemporary v = null;
7588 if (method == null && type.IsStructOrEnum) {
7589 // TODO: Use temporary variable from pool
7590 v = new LocalTemporary (type);
7597 public override void EmitStatement (EmitContext ec)
7599 LocalTemporary v = null;
7600 if (method == null && TypeSpec.IsValueType (type)) {
7601 // TODO: Use temporary variable from pool
7602 v = new LocalTemporary (type);
7606 ec.Emit (OpCodes.Pop);
7609 public override void FlowAnalysis (FlowAnalysisContext fc)
7611 if (arguments != null)
7612 arguments.FlowAnalysis (fc);
7615 public void AddressOf (EmitContext ec, AddressOp mode)
7617 EmitAddressOf (ec, mode);
7620 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7622 LocalTemporary value_target = new LocalTemporary (type);
7624 if (type is TypeParameterSpec) {
7625 DoEmitTypeParameter (ec);
7626 value_target.Store (ec);
7627 value_target.AddressOf (ec, mode);
7628 return value_target;
7631 value_target.AddressOf (ec, AddressOp.Store);
7633 if (method == null) {
7634 ec.Emit (OpCodes.Initobj, type);
7636 if (arguments != null)
7637 arguments.Emit (ec);
7639 ec.Emit (OpCodes.Call, method);
7642 value_target.AddressOf (ec, mode);
7643 return value_target;
7646 protected override void CloneTo (CloneContext clonectx, Expression t)
7648 New target = (New) t;
7650 target.RequestedType = RequestedType.Clone (clonectx);
7651 if (arguments != null){
7652 target.arguments = arguments.Clone (clonectx);
7656 public override SLE.Expression MakeExpression (BuilderContext ctx)
7659 return base.MakeExpression (ctx);
7661 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7665 public override object Accept (StructuralVisitor visitor)
7667 return visitor.Visit (this);
7672 // Array initializer expression, the expression is allowed in
7673 // variable or field initialization only which makes it tricky as
7674 // the type has to be infered based on the context either from field
7675 // type or variable type (think of multiple declarators)
7677 public class ArrayInitializer : Expression
7679 List<Expression> elements;
7680 BlockVariable variable;
7682 public ArrayInitializer (List<Expression> init, Location loc)
7688 public ArrayInitializer (int count, Location loc)
7689 : this (new List<Expression> (count), loc)
7693 public ArrayInitializer (Location loc)
7701 get { return elements.Count; }
7704 public List<Expression> Elements {
7710 public Expression this [int index] {
7712 return elements [index];
7716 public BlockVariable VariableDeclaration {
7727 public void Add (Expression expr)
7729 elements.Add (expr);
7732 public override bool ContainsEmitWithAwait ()
7734 throw new NotSupportedException ();
7737 public override Expression CreateExpressionTree (ResolveContext ec)
7739 throw new NotSupportedException ("ET");
7742 protected override void CloneTo (CloneContext clonectx, Expression t)
7744 var target = (ArrayInitializer) t;
7746 target.elements = new List<Expression> (elements.Count);
7747 foreach (var element in elements)
7748 target.elements.Add (element.Clone (clonectx));
7751 protected override Expression DoResolve (ResolveContext rc)
7753 var current_field = rc.CurrentMemberDefinition as FieldBase;
7754 TypeExpression type;
7755 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7756 type = new TypeExpression (current_field.MemberType, current_field.Location);
7757 } else if (variable != null) {
7758 if (variable.TypeExpression is VarExpr) {
7759 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7760 return EmptyExpression.Null;
7763 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7765 throw new NotImplementedException ("Unexpected array initializer context");
7768 return new ArrayCreation (type, this).Resolve (rc);
7771 public override void Emit (EmitContext ec)
7773 throw new InternalErrorException ("Missing Resolve call");
7776 public override void FlowAnalysis (FlowAnalysisContext fc)
7778 throw new InternalErrorException ("Missing Resolve call");
7781 public override object Accept (StructuralVisitor visitor)
7783 return visitor.Visit (this);
7788 /// 14.5.10.2: Represents an array creation expression.
7792 /// There are two possible scenarios here: one is an array creation
7793 /// expression that specifies the dimensions and optionally the
7794 /// initialization data and the other which does not need dimensions
7795 /// specified but where initialization data is mandatory.
7797 public class ArrayCreation : Expression
7799 FullNamedExpression requested_base_type;
7800 ArrayInitializer initializers;
7803 // The list of Argument types.
7804 // This is used to construct the `newarray' or constructor signature
7806 protected List<Expression> arguments;
7808 protected TypeSpec array_element_type;
7810 protected int dimensions;
7811 protected readonly ComposedTypeSpecifier rank;
7812 Expression first_emit;
7813 LocalTemporary first_emit_temp;
7815 protected List<Expression> array_data;
7817 Dictionary<int, int> bounds;
7820 // The number of constants in array initializers
7821 int const_initializers_count;
7822 bool only_constant_initializers;
7824 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7825 : this (requested_base_type, rank, initializers, l)
7827 arguments = new List<Expression> (exprs);
7828 num_arguments = arguments.Count;
7832 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7834 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7836 this.requested_base_type = requested_base_type;
7838 this.initializers = initializers;
7842 num_arguments = rank.Dimension;
7846 // For compiler generated single dimensional arrays only
7848 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7849 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7854 // For expressions like int[] foo = { 1, 2, 3 };
7856 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7857 : this (requested_base_type, null, initializers, initializers.Location)
7861 public ComposedTypeSpecifier Rank {
7867 public FullNamedExpression TypeExpression {
7869 return this.requested_base_type;
7873 public ArrayInitializer Initializers {
7875 return this.initializers;
7879 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7881 if (initializers != null && bounds == null) {
7883 // We use this to store all the data values in the order in which we
7884 // will need to store them in the byte blob later
7886 array_data = new List<Expression> (probe.Count);
7887 bounds = new Dictionary<int, int> ();
7890 if (specified_dims) {
7891 Expression a = arguments [idx];
7896 a = ConvertExpressionToArrayIndex (ec, a);
7902 if (initializers != null) {
7903 Constant c = a as Constant;
7904 if (c == null && a is ArrayIndexCast)
7905 c = ((ArrayIndexCast) a).Child as Constant;
7908 ec.Report.Error (150, a.Location, "A constant value is expected");
7914 value = System.Convert.ToInt32 (c.GetValue ());
7916 ec.Report.Error (150, a.Location, "A constant value is expected");
7920 // TODO: probe.Count does not fit ulong in
7921 if (value != probe.Count) {
7922 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7926 bounds[idx] = value;
7930 if (initializers == null)
7933 for (int i = 0; i < probe.Count; ++i) {
7935 if (o is ArrayInitializer) {
7936 var sub_probe = o as ArrayInitializer;
7937 if (idx + 1 >= dimensions){
7938 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7942 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7943 if (!bounds.ContainsKey(idx + 1))
7944 bounds[idx + 1] = sub_probe.Count;
7946 if (bounds[idx + 1] != sub_probe.Count) {
7947 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7951 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7954 } else if (child_bounds > 1) {
7955 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7957 Expression element = ResolveArrayElement (ec, o);
7958 if (element == null)
7961 // Initializers with the default values can be ignored
7962 Constant c = element as Constant;
7964 if (!c.IsDefaultInitializer (array_element_type)) {
7965 ++const_initializers_count;
7968 only_constant_initializers = false;
7971 array_data.Add (element);
7978 public override bool ContainsEmitWithAwait ()
7980 foreach (var arg in arguments) {
7981 if (arg.ContainsEmitWithAwait ())
7985 return InitializersContainAwait ();
7988 public override Expression CreateExpressionTree (ResolveContext ec)
7992 if (array_data == null) {
7993 args = new Arguments (arguments.Count + 1);
7994 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7995 foreach (Expression a in arguments)
7996 args.Add (new Argument (a.CreateExpressionTree (ec)));
7998 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8001 if (dimensions > 1) {
8002 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8006 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8007 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8008 if (array_data != null) {
8009 for (int i = 0; i < array_data.Count; ++i) {
8010 Expression e = array_data [i];
8011 args.Add (new Argument (e.CreateExpressionTree (ec)));
8015 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8018 void UpdateIndices (ResolveContext rc)
8021 for (var probe = initializers; probe != null;) {
8022 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8024 bounds[i++] = probe.Count;
8026 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8027 probe = (ArrayInitializer) probe[0];
8028 } else if (dimensions > i) {
8036 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8038 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8041 public override void FlowAnalysis (FlowAnalysisContext fc)
8043 foreach (var arg in arguments)
8044 arg.FlowAnalysis (fc);
8046 if (array_data != null) {
8047 foreach (var ad in array_data)
8048 ad.FlowAnalysis (fc);
8052 bool InitializersContainAwait ()
8054 if (array_data == null)
8057 foreach (var expr in array_data) {
8058 if (expr.ContainsEmitWithAwait ())
8065 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8067 element = element.Resolve (ec);
8068 if (element == null)
8071 if (element is CompoundAssign.TargetExpression) {
8072 if (first_emit != null)
8073 throw new InternalErrorException ("Can only handle one mutator at a time");
8074 first_emit = element;
8075 element = first_emit_temp = new LocalTemporary (element.Type);
8078 return Convert.ImplicitConversionRequired (
8079 ec, element, array_element_type, loc);
8082 protected bool ResolveInitializers (ResolveContext ec)
8085 only_constant_initializers = true;
8088 if (arguments != null) {
8090 for (int i = 0; i < arguments.Count; ++i) {
8091 res &= CheckIndices (ec, initializers, i, true, dimensions);
8092 if (initializers != null)
8099 arguments = new List<Expression> ();
8101 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8110 // Resolved the type of the array
8112 bool ResolveArrayType (ResolveContext ec)
8117 FullNamedExpression array_type_expr;
8118 if (num_arguments > 0) {
8119 array_type_expr = new ComposedCast (requested_base_type, rank);
8121 array_type_expr = requested_base_type;
8124 type = array_type_expr.ResolveAsType (ec);
8125 if (array_type_expr == null)
8128 var ac = type as ArrayContainer;
8130 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8134 array_element_type = ac.Element;
8135 dimensions = ac.Rank;
8140 protected override Expression DoResolve (ResolveContext ec)
8145 if (!ResolveArrayType (ec))
8149 // validate the initializers and fill in any missing bits
8151 if (!ResolveInitializers (ec))
8154 eclass = ExprClass.Value;
8158 byte [] MakeByteBlob ()
8163 int count = array_data.Count;
8165 TypeSpec element_type = array_element_type;
8166 if (element_type.IsEnum)
8167 element_type = EnumSpec.GetUnderlyingType (element_type);
8169 factor = BuiltinTypeSpec.GetSize (element_type);
8171 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8173 data = new byte [(count * factor + 3) & ~3];
8176 for (int i = 0; i < count; ++i) {
8177 var c = array_data[i] as Constant;
8183 object v = c.GetValue ();
8185 switch (element_type.BuiltinType) {
8186 case BuiltinTypeSpec.Type.Long:
8187 long lval = (long) v;
8189 for (int j = 0; j < factor; ++j) {
8190 data[idx + j] = (byte) (lval & 0xFF);
8194 case BuiltinTypeSpec.Type.ULong:
8195 ulong ulval = (ulong) v;
8197 for (int j = 0; j < factor; ++j) {
8198 data[idx + j] = (byte) (ulval & 0xFF);
8199 ulval = (ulval >> 8);
8202 case BuiltinTypeSpec.Type.Float:
8203 var fval = SingleConverter.SingleToInt32Bits((float) v);
8205 data[idx] = (byte) (fval & 0xff);
8206 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8207 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8208 data[idx + 3] = (byte) (fval >> 24);
8210 case BuiltinTypeSpec.Type.Double:
8211 element = BitConverter.GetBytes ((double) v);
8213 for (int j = 0; j < factor; ++j)
8214 data[idx + j] = element[j];
8216 // FIXME: Handle the ARM float format.
8217 if (!BitConverter.IsLittleEndian)
8218 System.Array.Reverse (data, idx, 8);
8220 case BuiltinTypeSpec.Type.Char:
8221 int chval = (int) ((char) v);
8223 data[idx] = (byte) (chval & 0xff);
8224 data[idx + 1] = (byte) (chval >> 8);
8226 case BuiltinTypeSpec.Type.Short:
8227 int sval = (int) ((short) v);
8229 data[idx] = (byte) (sval & 0xff);
8230 data[idx + 1] = (byte) (sval >> 8);
8232 case BuiltinTypeSpec.Type.UShort:
8233 int usval = (int) ((ushort) v);
8235 data[idx] = (byte) (usval & 0xff);
8236 data[idx + 1] = (byte) (usval >> 8);
8238 case BuiltinTypeSpec.Type.Int:
8241 data[idx] = (byte) (val & 0xff);
8242 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8243 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8244 data[idx + 3] = (byte) (val >> 24);
8246 case BuiltinTypeSpec.Type.UInt:
8247 uint uval = (uint) v;
8249 data[idx] = (byte) (uval & 0xff);
8250 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8251 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8252 data[idx + 3] = (byte) (uval >> 24);
8254 case BuiltinTypeSpec.Type.SByte:
8255 data[idx] = (byte) (sbyte) v;
8257 case BuiltinTypeSpec.Type.Byte:
8258 data[idx] = (byte) v;
8260 case BuiltinTypeSpec.Type.Bool:
8261 data[idx] = (byte) ((bool) v ? 1 : 0);
8263 case BuiltinTypeSpec.Type.Decimal:
8264 int[] bits = Decimal.GetBits ((decimal) v);
8267 // FIXME: For some reason, this doesn't work on the MS runtime.
8268 int[] nbits = new int[4];
8274 for (int j = 0; j < 4; j++) {
8275 data[p++] = (byte) (nbits[j] & 0xff);
8276 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8277 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8278 data[p++] = (byte) (nbits[j] >> 24);
8282 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8291 public override SLE.Expression MakeExpression (BuilderContext ctx)
8294 return base.MakeExpression (ctx);
8296 var initializers = new SLE.Expression [array_data.Count];
8297 for (var i = 0; i < initializers.Length; i++) {
8298 if (array_data [i] == null)
8299 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8301 initializers [i] = array_data [i].MakeExpression (ctx);
8304 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8309 // Emits the initializers for the array
8311 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8313 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8318 // First, the static data
8320 byte [] data = MakeByteBlob ();
8321 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8323 if (stackArray == null) {
8324 ec.Emit (OpCodes.Dup);
8326 stackArray.Emit (ec);
8329 ec.Emit (OpCodes.Ldtoken, fb);
8330 ec.Emit (OpCodes.Call, m);
8335 // Emits pieces of the array that can not be computed at compile
8336 // time (variables and string locations).
8338 // This always expect the top value on the stack to be the array
8340 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8342 int dims = bounds.Count;
8343 var current_pos = new int [dims];
8345 for (int i = 0; i < array_data.Count; i++){
8347 Expression e = array_data [i];
8348 var c = e as Constant;
8350 // Constant can be initialized via StaticInitializer
8351 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8355 if (stackArray != null) {
8356 if (e.ContainsEmitWithAwait ()) {
8357 e = e.EmitToField (ec);
8360 stackArray.EmitLoad (ec);
8362 ec.Emit (OpCodes.Dup);
8365 for (int idx = 0; idx < dims; idx++)
8366 ec.EmitInt (current_pos [idx]);
8369 // If we are dealing with a struct, get the
8370 // address of it, so we can store it.
8372 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8373 ec.Emit (OpCodes.Ldelema, etype);
8377 ec.EmitArrayStore ((ArrayContainer) type);
8383 for (int j = dims - 1; j >= 0; j--){
8385 if (current_pos [j] < bounds [j])
8387 current_pos [j] = 0;
8391 if (stackArray != null)
8392 stackArray.PrepareCleanup (ec);
8395 public override void Emit (EmitContext ec)
8397 var await_field = EmitToFieldSource (ec);
8398 if (await_field != null)
8399 await_field.Emit (ec);
8402 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8404 if (first_emit != null) {
8405 first_emit.Emit (ec);
8406 first_emit_temp.Store (ec);
8409 StackFieldExpr await_stack_field;
8410 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8411 await_stack_field = ec.GetTemporaryField (type);
8414 await_stack_field = null;
8417 EmitExpressionsList (ec, arguments);
8419 ec.EmitArrayNew ((ArrayContainer) type);
8421 if (initializers == null)
8422 return await_stack_field;
8424 if (await_stack_field != null)
8425 await_stack_field.EmitAssignFromStack (ec);
8429 // Emit static initializer for arrays which contain more than 2 items and
8430 // the static initializer will initialize at least 25% of array values or there
8431 // is more than 10 items to be initialized
8433 // NOTE: const_initializers_count does not contain default constant values.
8435 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8436 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8437 EmitStaticInitializers (ec, await_stack_field);
8439 if (!only_constant_initializers)
8440 EmitDynamicInitializers (ec, false, await_stack_field);
8444 EmitDynamicInitializers (ec, true, await_stack_field);
8447 if (first_emit_temp != null)
8448 first_emit_temp.Release (ec);
8450 return await_stack_field;
8453 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8455 // no multi dimensional or jagged arrays
8456 if (arguments.Count != 1 || array_element_type.IsArray) {
8457 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8461 // No array covariance, except for array -> object
8462 if (type != targetType) {
8463 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8464 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8468 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8469 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8474 // Single dimensional array of 0 size
8475 if (array_data == null) {
8476 IntConstant ic = arguments[0] as IntConstant;
8477 if (ic == null || !ic.IsDefaultValue) {
8478 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8486 enc.Encode (array_data.Count);
8487 foreach (var element in array_data) {
8488 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8492 protected override void CloneTo (CloneContext clonectx, Expression t)
8494 ArrayCreation target = (ArrayCreation) t;
8496 if (requested_base_type != null)
8497 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8499 if (arguments != null){
8500 target.arguments = new List<Expression> (arguments.Count);
8501 foreach (Expression e in arguments)
8502 target.arguments.Add (e.Clone (clonectx));
8505 if (initializers != null)
8506 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8509 public override object Accept (StructuralVisitor visitor)
8511 return visitor.Visit (this);
8516 // Represents an implicitly typed array epxression
8518 class ImplicitlyTypedArrayCreation : ArrayCreation
8520 TypeInferenceContext best_type_inference;
8522 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8523 : base (null, rank, initializers, loc)
8527 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8528 : base (null, initializers, loc)
8532 protected override Expression DoResolve (ResolveContext ec)
8537 dimensions = rank.Dimension;
8539 best_type_inference = new TypeInferenceContext ();
8541 if (!ResolveInitializers (ec))
8544 best_type_inference.FixAllTypes (ec);
8545 array_element_type = best_type_inference.InferredTypeArguments[0];
8546 best_type_inference = null;
8548 if (array_element_type == null ||
8549 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8550 arguments.Count != rank.Dimension) {
8551 ec.Report.Error (826, loc,
8552 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8557 // At this point we found common base type for all initializer elements
8558 // but we have to be sure that all static initializer elements are of
8561 UnifyInitializerElement (ec);
8563 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8564 eclass = ExprClass.Value;
8569 // Converts static initializer only
8571 void UnifyInitializerElement (ResolveContext ec)
8573 for (int i = 0; i < array_data.Count; ++i) {
8574 Expression e = array_data[i];
8576 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8580 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8582 element = element.Resolve (ec);
8583 if (element != null)
8584 best_type_inference.AddCommonTypeBound (element.Type);
8590 sealed class CompilerGeneratedThis : This
8592 public CompilerGeneratedThis (TypeSpec type, Location loc)
8598 protected override Expression DoResolve (ResolveContext rc)
8600 eclass = ExprClass.Variable;
8602 var block = rc.CurrentBlock;
8603 if (block != null) {
8604 var top = block.ParametersBlock.TopBlock;
8605 if (top.ThisVariable != null)
8606 variable_info = top.ThisVariable.VariableInfo;
8613 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8615 return DoResolve (rc);
8618 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8625 /// Represents the `this' construct
8628 public class This : VariableReference
8630 sealed class ThisVariable : ILocalVariable
8632 public static readonly ILocalVariable Instance = new ThisVariable ();
8634 public void Emit (EmitContext ec)
8639 public void EmitAssign (EmitContext ec)
8641 throw new InvalidOperationException ();
8644 public void EmitAddressOf (EmitContext ec)
8650 protected VariableInfo variable_info;
8652 public This (Location loc)
8659 public override string Name {
8660 get { return "this"; }
8663 public override bool IsLockedByStatement {
8671 public override bool IsRef {
8672 get { return type.IsStruct; }
8675 public override bool IsSideEffectFree {
8681 protected override ILocalVariable Variable {
8682 get { return ThisVariable.Instance; }
8685 public override VariableInfo VariableInfo {
8686 get { return variable_info; }
8689 public override bool IsFixed {
8690 get { return false; }
8695 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8698 // It's null for all cases when we don't need to check `this'
8699 // definitive assignment
8701 if (variable_info == null)
8704 if (fc.IsDefinitelyAssigned (variable_info))
8707 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8710 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8712 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8713 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8714 } else if (ec.CurrentAnonymousMethod != null) {
8715 ec.Report.Error (1673, loc,
8716 "Anonymous methods inside structs cannot access instance members of `this'. " +
8717 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8719 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8723 public override void FlowAnalysis (FlowAnalysisContext fc)
8725 CheckStructThisDefiniteAssignment (fc);
8728 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8733 AnonymousMethodStorey storey = ae.Storey;
8734 return storey != null ? storey.HoistedThis : null;
8737 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8739 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8742 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8745 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8751 public virtual void ResolveBase (ResolveContext ec)
8753 eclass = ExprClass.Variable;
8754 type = ec.CurrentType;
8756 if (!IsThisAvailable (ec, false)) {
8757 Error_ThisNotAvailable (ec);
8761 var block = ec.CurrentBlock;
8762 if (block != null) {
8763 var top = block.ParametersBlock.TopBlock;
8764 if (top.ThisVariable != null)
8765 variable_info = top.ThisVariable.VariableInfo;
8767 AnonymousExpression am = ec.CurrentAnonymousMethod;
8768 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8770 // Hoisted this is almost like hoisted variable but not exactly. When
8771 // there is no variable hoisted we can simply emit an instance method
8772 // without lifting this into a storey. Unfotunatelly this complicates
8773 // things in other cases because we don't know where this will be hoisted
8774 // until top-level block is fully resolved
8776 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8777 am.SetHasThisAccess ();
8782 protected override Expression DoResolve (ResolveContext ec)
8788 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8790 if (eclass == ExprClass.Unresolved)
8794 if (right_side == EmptyExpression.UnaryAddress)
8795 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8796 else if (right_side == EmptyExpression.OutAccess)
8797 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8799 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8805 public override int GetHashCode()
8807 throw new NotImplementedException ();
8810 public override bool Equals (object obj)
8812 This t = obj as This;
8819 protected override void CloneTo (CloneContext clonectx, Expression t)
8824 public override void SetHasAddressTaken ()
8829 public override object Accept (StructuralVisitor visitor)
8831 return visitor.Visit (this);
8836 /// Represents the `__arglist' construct
8838 public class ArglistAccess : Expression
8840 public ArglistAccess (Location loc)
8845 protected override void CloneTo (CloneContext clonectx, Expression target)
8850 public override bool ContainsEmitWithAwait ()
8855 public override Expression CreateExpressionTree (ResolveContext ec)
8857 throw new NotSupportedException ("ET");
8860 protected override Expression DoResolve (ResolveContext ec)
8862 eclass = ExprClass.Variable;
8863 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8865 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8866 ec.Report.Error (190, loc,
8867 "The __arglist construct is valid only within a variable argument method");
8873 public override void Emit (EmitContext ec)
8875 ec.Emit (OpCodes.Arglist);
8878 public override object Accept (StructuralVisitor visitor)
8880 return visitor.Visit (this);
8885 /// Represents the `__arglist (....)' construct
8887 public class Arglist : Expression
8889 Arguments arguments;
8891 public Arglist (Location loc)
8896 public Arglist (Arguments args, Location l)
8902 public Arguments Arguments {
8908 public MetaType[] ArgumentTypes {
8910 if (arguments == null)
8911 return MetaType.EmptyTypes;
8913 var retval = new MetaType[arguments.Count];
8914 for (int i = 0; i < retval.Length; i++)
8915 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8921 public override bool ContainsEmitWithAwait ()
8923 throw new NotImplementedException ();
8926 public override Expression CreateExpressionTree (ResolveContext ec)
8928 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8932 protected override Expression DoResolve (ResolveContext ec)
8934 eclass = ExprClass.Variable;
8935 type = InternalType.Arglist;
8936 if (arguments != null) {
8937 bool dynamic; // Can be ignored as there is always only 1 overload
8938 arguments.Resolve (ec, out dynamic);
8944 public override void Emit (EmitContext ec)
8946 if (arguments != null)
8947 arguments.Emit (ec);
8950 protected override void CloneTo (CloneContext clonectx, Expression t)
8952 Arglist target = (Arglist) t;
8954 if (arguments != null)
8955 target.arguments = arguments.Clone (clonectx);
8958 public override object Accept (StructuralVisitor visitor)
8960 return visitor.Visit (this);
8964 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8966 FullNamedExpression texpr;
8968 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8975 public FullNamedExpression TypeExpression {
8981 public override bool ContainsEmitWithAwait ()
8986 public void AddressOf (EmitContext ec, AddressOp mode)
8989 ec.Emit (OpCodes.Refanyval, type);
8992 protected override Expression DoResolve (ResolveContext rc)
8994 expr = expr.Resolve (rc);
8995 type = texpr.ResolveAsType (rc);
8996 if (expr == null || type == null)
8999 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9000 eclass = ExprClass.Variable;
9004 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9006 return DoResolve (rc);
9009 public override void Emit (EmitContext ec)
9012 ec.Emit (OpCodes.Refanyval, type);
9013 ec.EmitLoadFromPtr (type);
9016 public void Emit (EmitContext ec, bool leave_copy)
9018 throw new NotImplementedException ();
9021 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9024 ec.Emit (OpCodes.Refanyval, type);
9027 LocalTemporary temporary = null;
9029 ec.Emit (OpCodes.Dup);
9030 temporary = new LocalTemporary (source.Type);
9031 temporary.Store (ec);
9034 ec.EmitStoreFromPtr (type);
9036 if (temporary != null) {
9037 temporary.Emit (ec);
9038 temporary.Release (ec);
9042 public override object Accept (StructuralVisitor visitor)
9044 return visitor.Visit (this);
9048 public class RefTypeExpr : ShimExpression
9050 public RefTypeExpr (Expression expr, Location loc)
9056 protected override Expression DoResolve (ResolveContext rc)
9058 expr = expr.Resolve (rc);
9062 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9066 type = rc.BuiltinTypes.Type;
9067 eclass = ExprClass.Value;
9071 public override void Emit (EmitContext ec)
9074 ec.Emit (OpCodes.Refanytype);
9075 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9077 ec.Emit (OpCodes.Call, m);
9080 public override object Accept (StructuralVisitor visitor)
9082 return visitor.Visit (this);
9086 public class MakeRefExpr : ShimExpression
9088 public MakeRefExpr (Expression expr, Location loc)
9094 public override bool ContainsEmitWithAwait ()
9096 throw new NotImplementedException ();
9099 protected override Expression DoResolve (ResolveContext rc)
9101 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9102 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9103 eclass = ExprClass.Value;
9107 public override void Emit (EmitContext ec)
9109 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9110 ec.Emit (OpCodes.Mkrefany, expr.Type);
9113 public override object Accept (StructuralVisitor visitor)
9115 return visitor.Visit (this);
9120 /// Implements the typeof operator
9122 public class TypeOf : Expression {
9123 FullNamedExpression QueriedType;
9126 public TypeOf (FullNamedExpression queried_type, Location l)
9128 QueriedType = queried_type;
9133 // Use this constructor for any compiler generated typeof expression
9135 public TypeOf (TypeSpec type, Location loc)
9137 this.typearg = type;
9143 public override bool IsSideEffectFree {
9149 public TypeSpec TypeArgument {
9155 public FullNamedExpression TypeExpression {
9164 protected override void CloneTo (CloneContext clonectx, Expression t)
9166 TypeOf target = (TypeOf) t;
9167 if (QueriedType != null)
9168 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9171 public override bool ContainsEmitWithAwait ()
9176 public override Expression CreateExpressionTree (ResolveContext ec)
9178 Arguments args = new Arguments (2);
9179 args.Add (new Argument (this));
9180 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9181 return CreateExpressionFactoryCall (ec, "Constant", args);
9184 protected override Expression DoResolve (ResolveContext ec)
9186 if (eclass != ExprClass.Unresolved)
9189 if (typearg == null) {
9191 // Pointer types are allowed without explicit unsafe, they are just tokens
9193 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9194 typearg = QueriedType.ResolveAsType (ec, true);
9197 if (typearg == null)
9200 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9201 ec.Report.Error (1962, QueriedType.Location,
9202 "The typeof operator cannot be used on the dynamic type");
9206 type = ec.BuiltinTypes.Type;
9208 // Even though what is returned is a type object, it's treated as a value by the compiler.
9209 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9210 eclass = ExprClass.Value;
9214 static bool ContainsDynamicType (TypeSpec type)
9216 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9219 var element_container = type as ElementTypeSpec;
9220 if (element_container != null)
9221 return ContainsDynamicType (element_container.Element);
9223 foreach (var t in type.TypeArguments) {
9224 if (ContainsDynamicType (t)) {
9232 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9234 // Target type is not System.Type therefore must be object
9235 // and we need to use different encoding sequence
9236 if (targetType != type)
9239 if (typearg is InflatedTypeSpec) {
9242 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9243 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9244 typearg.GetSignatureForError ());
9248 gt = gt.DeclaringType;
9249 } while (gt != null);
9252 if (ContainsDynamicType (typearg)) {
9253 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9257 enc.EncodeTypeName (typearg);
9260 public override void Emit (EmitContext ec)
9262 ec.Emit (OpCodes.Ldtoken, typearg);
9263 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9265 ec.Emit (OpCodes.Call, m);
9268 public override object Accept (StructuralVisitor visitor)
9270 return visitor.Visit (this);
9274 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9276 public TypeOfMethod (MethodSpec method, Location loc)
9277 : base (method, loc)
9281 protected override Expression DoResolve (ResolveContext ec)
9283 if (member.IsConstructor) {
9284 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9286 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9292 return base.DoResolve (ec);
9295 public override void Emit (EmitContext ec)
9297 ec.Emit (OpCodes.Ldtoken, member);
9300 ec.Emit (OpCodes.Castclass, type);
9303 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9305 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9308 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9310 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9314 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9316 protected readonly T member;
9318 protected TypeOfMember (T member, Location loc)
9320 this.member = member;
9324 public override bool IsSideEffectFree {
9330 public override bool ContainsEmitWithAwait ()
9335 public override Expression CreateExpressionTree (ResolveContext ec)
9337 Arguments args = new Arguments (2);
9338 args.Add (new Argument (this));
9339 args.Add (new Argument (new TypeOf (type, loc)));
9340 return CreateExpressionFactoryCall (ec, "Constant", args);
9343 protected override Expression DoResolve (ResolveContext ec)
9345 eclass = ExprClass.Value;
9349 public override void Emit (EmitContext ec)
9351 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9352 PredefinedMember<MethodSpec> p;
9354 p = GetTypeFromHandleGeneric (ec);
9355 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9357 p = GetTypeFromHandle (ec);
9360 var mi = p.Resolve (loc);
9362 ec.Emit (OpCodes.Call, mi);
9365 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9366 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9369 sealed class TypeOfField : TypeOfMember<FieldSpec>
9371 public TypeOfField (FieldSpec field, Location loc)
9376 protected override Expression DoResolve (ResolveContext ec)
9378 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9382 return base.DoResolve (ec);
9385 public override void Emit (EmitContext ec)
9387 ec.Emit (OpCodes.Ldtoken, member);
9391 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9393 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9396 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9398 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9403 /// Implements the sizeof expression
9405 public class SizeOf : Expression {
9406 readonly Expression texpr;
9407 TypeSpec type_queried;
9409 public SizeOf (Expression queried_type, Location l)
9411 this.texpr = queried_type;
9415 public override bool IsSideEffectFree {
9421 public Expression TypeExpression {
9427 public override bool ContainsEmitWithAwait ()
9432 public override Expression CreateExpressionTree (ResolveContext ec)
9434 Error_PointerInsideExpressionTree (ec);
9438 protected override Expression DoResolve (ResolveContext ec)
9440 type_queried = texpr.ResolveAsType (ec);
9441 if (type_queried == null)
9444 if (type_queried.IsEnum)
9445 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9447 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9449 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9452 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9457 ec.Report.Error (233, loc,
9458 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9459 type_queried.GetSignatureForError ());
9462 type = ec.BuiltinTypes.Int;
9463 eclass = ExprClass.Value;
9467 public override void Emit (EmitContext ec)
9469 ec.Emit (OpCodes.Sizeof, type_queried);
9472 protected override void CloneTo (CloneContext clonectx, Expression t)
9476 public override object Accept (StructuralVisitor visitor)
9478 return visitor.Visit (this);
9483 /// Implements the qualified-alias-member (::) expression.
9485 public class QualifiedAliasMember : MemberAccess
9487 readonly string alias;
9488 public static readonly string GlobalAlias = "global";
9490 public QualifiedAliasMember (string alias, string identifier, Location l)
9491 : base (null, identifier, l)
9496 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9497 : base (null, identifier, targs, l)
9502 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9503 : base (null, identifier, arity, l)
9508 public string Alias {
9514 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9516 if (alias == GlobalAlias)
9517 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9519 int errors = mc.Module.Compiler.Report.Errors;
9520 var expr = mc.LookupNamespaceAlias (alias);
9522 if (errors == mc.Module.Compiler.Report.Errors)
9523 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9531 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9533 expr = CreateExpressionFromAlias (mc);
9537 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9540 protected override Expression DoResolve (ResolveContext rc)
9542 return ResolveAsTypeOrNamespace (rc, false);
9545 public override string GetSignatureForError ()
9548 if (targs != null) {
9549 name = Name + "<" + targs.GetSignatureForError () + ">";
9552 return alias + "::" + name;
9555 public override bool HasConditionalAccess ()
9560 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9562 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9563 rc.Module.Compiler.Report.Error (687, loc,
9564 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9565 GetSignatureForError ());
9570 return DoResolve (rc);
9573 protected override void CloneTo (CloneContext clonectx, Expression t)
9578 public override object Accept (StructuralVisitor visitor)
9580 return visitor.Visit (this);
9585 /// Implements the member access expression
9587 public class MemberAccess : ATypeNameExpression
9589 protected Expression expr;
9591 public MemberAccess (Expression expr, string id)
9592 : base (id, expr.Location)
9597 public MemberAccess (Expression expr, string identifier, Location loc)
9598 : base (identifier, loc)
9603 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9604 : base (identifier, args, loc)
9609 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9610 : base (identifier, arity, loc)
9615 public Expression LeftExpression {
9621 public override Location StartLocation {
9623 return expr == null ? loc : expr.StartLocation;
9627 protected override Expression DoResolve (ResolveContext rc)
9629 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9631 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9636 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9638 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9640 if (e is TypeExpr) {
9641 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9646 e = e.ResolveLValue (rc, rhs);
9651 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9653 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9654 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9656 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9659 public override bool HasConditionalAccess ()
9661 return LeftExpression.HasConditionalAccess ();
9664 public static bool IsValidDotExpression (TypeSpec type)
9666 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9667 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9669 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9672 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9674 var sn = expr as SimpleName;
9675 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9678 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9681 // Resolve expression which does have type set as we need expression type
9682 // with disable flow analysis as we don't know whether left side expression
9683 // is used as variable or type
9685 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9686 expr = expr.Resolve (rc);
9687 } else if (expr is TypeParameterExpr) {
9688 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9692 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9693 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9694 expr = expr.Resolve (rc, flags);
9697 expr = expr.Resolve (rc, flags);
9704 var ns = expr as NamespaceExpression;
9706 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9708 if (retval == null) {
9709 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9714 if (HasTypeArguments)
9715 return new GenericTypeExpr (retval.Type, targs, loc);
9717 targs.Resolve (rc, false);
9724 TypeSpec expr_type = expr.Type;
9725 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9726 me = expr as MemberExpr;
9728 me.ResolveInstanceExpression (rc, null);
9730 Arguments args = new Arguments (1);
9731 args.Add (new Argument (expr));
9732 return new DynamicMemberBinder (Name, args, loc);
9735 var cma = this as ConditionalMemberAccess;
9737 if (!IsNullPropagatingValid (expr.Type)) {
9738 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9742 if (expr_type.IsNullableType) {
9743 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9744 expr_type = expr.Type;
9748 if (!IsValidDotExpression (expr_type)) {
9749 Error_OperatorCannotBeApplied (rc, expr_type);
9753 var lookup_arity = Arity;
9754 bool errorMode = false;
9755 Expression member_lookup;
9757 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9758 if (member_lookup == null) {
9760 // Try to look for extension method when member lookup failed
9762 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9763 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9764 if (methods != null) {
9765 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9766 if (HasTypeArguments) {
9767 if (!targs.Resolve (rc, false))
9770 emg.SetTypeArguments (rc, targs);
9774 emg.ConditionalAccess = true;
9776 // TODO: it should really skip the checks bellow
9777 return emg.Resolve (rc);
9783 if (member_lookup == null) {
9784 var dep = expr_type.GetMissingDependencies ();
9786 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9787 } else if (expr is TypeExpr) {
9788 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9790 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9796 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9797 // Leave it to overload resolution to report correct error
9798 } else if (!(member_lookup is TypeExpr)) {
9799 // TODO: rc.SymbolRelatedToPreviousError
9800 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9805 if (member_lookup != null)
9809 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9813 TypeExpr texpr = member_lookup as TypeExpr;
9814 if (texpr != null) {
9815 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9816 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9817 Name, texpr.GetSignatureForError ());
9820 if (!texpr.Type.IsAccessible (rc)) {
9821 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9822 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9826 if (HasTypeArguments) {
9827 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9830 return member_lookup;
9833 me = member_lookup as MemberExpr;
9835 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9840 me.ConditionalAccess = true;
9843 me = me.ResolveMemberAccess (rc, expr, sn);
9846 if (!targs.Resolve (rc, false))
9849 me.SetTypeArguments (rc, targs);
9855 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9857 FullNamedExpression fexpr = expr as FullNamedExpression;
9858 if (fexpr == null) {
9859 expr.ResolveAsType (rc);
9863 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9865 if (expr_resolved == null)
9868 var ns = expr_resolved as NamespaceExpression;
9870 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9872 if (retval == null) {
9873 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9874 } else if (Arity > 0) {
9875 if (HasTypeArguments) {
9876 retval = new GenericTypeExpr (retval.Type, targs, loc);
9877 if (retval.ResolveAsType (rc) == null)
9880 targs.Resolve (rc, allowUnboundTypeArguments);
9882 retval = new GenericOpenTypeExpr (retval.Type, loc);
9889 var tnew_expr = expr_resolved.ResolveAsType (rc);
9890 if (tnew_expr == null)
9893 TypeSpec expr_type = tnew_expr;
9894 if (TypeManager.IsGenericParameter (expr_type)) {
9895 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9896 tnew_expr.GetSignatureForError ());
9900 var qam = this as QualifiedAliasMember;
9902 rc.Module.Compiler.Report.Error (431, loc,
9903 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9908 TypeSpec nested = null;
9909 while (expr_type != null) {
9910 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9911 if (nested == null) {
9912 if (expr_type == tnew_expr) {
9913 Error_IdentifierNotFound (rc, expr_type);
9917 expr_type = tnew_expr;
9918 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9919 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9923 if (nested.IsAccessible (rc))
9927 // Keep looking after inaccessible candidate but only if
9928 // we are not in same context as the definition itself
9930 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9933 expr_type = expr_type.BaseType;
9938 if (HasTypeArguments) {
9939 texpr = new GenericTypeExpr (nested, targs, loc);
9941 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9943 texpr = new GenericOpenTypeExpr (nested, loc);
9945 } else if (expr_resolved is GenericOpenTypeExpr) {
9946 texpr = new GenericOpenTypeExpr (nested, loc);
9948 texpr = new TypeExpression (nested, loc);
9951 if (texpr.ResolveAsType (rc) == null)
9957 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9959 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9961 if (nested != null) {
9962 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9966 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9967 if (any_other_member != null) {
9968 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9972 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9973 Name, expr_type.GetSignatureForError ());
9976 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9978 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9981 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9983 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9984 ec.Report.SymbolRelatedToPreviousError (type);
9986 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9988 // a using directive or an assembly reference
9990 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9992 missing = "an assembly reference";
9995 ec.Report.Error (1061, loc,
9996 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9997 type.GetSignatureForError (), name, missing);
10001 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10004 public override string GetSignatureForError ()
10006 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10009 protected override void CloneTo (CloneContext clonectx, Expression t)
10011 MemberAccess target = (MemberAccess) t;
10013 target.expr = expr.Clone (clonectx);
10016 public override object Accept (StructuralVisitor visitor)
10018 return visitor.Visit (this);
10022 public class ConditionalMemberAccess : MemberAccess
10024 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10025 : base (expr, identifier, args, loc)
10029 public override bool HasConditionalAccess ()
10036 /// Implements checked expressions
10038 public class CheckedExpr : Expression {
10040 public Expression Expr;
10042 public CheckedExpr (Expression e, Location l)
10048 public override bool ContainsEmitWithAwait ()
10050 return Expr.ContainsEmitWithAwait ();
10053 public override Expression CreateExpressionTree (ResolveContext ec)
10055 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10056 return Expr.CreateExpressionTree (ec);
10059 protected override Expression DoResolve (ResolveContext ec)
10061 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10062 Expr = Expr.Resolve (ec);
10067 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10070 eclass = Expr.eclass;
10075 public override void Emit (EmitContext ec)
10077 using (ec.With (EmitContext.Options.CheckedScope, true))
10081 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10083 using (ec.With (EmitContext.Options.CheckedScope, true))
10084 Expr.EmitBranchable (ec, target, on_true);
10087 public override void FlowAnalysis (FlowAnalysisContext fc)
10089 Expr.FlowAnalysis (fc);
10092 public override SLE.Expression MakeExpression (BuilderContext ctx)
10094 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10095 return Expr.MakeExpression (ctx);
10099 protected override void CloneTo (CloneContext clonectx, Expression t)
10101 CheckedExpr target = (CheckedExpr) t;
10103 target.Expr = Expr.Clone (clonectx);
10106 public override object Accept (StructuralVisitor visitor)
10108 return visitor.Visit (this);
10113 /// Implements the unchecked expression
10115 public class UnCheckedExpr : Expression {
10117 public Expression Expr;
10119 public UnCheckedExpr (Expression e, Location l)
10125 public override bool ContainsEmitWithAwait ()
10127 return Expr.ContainsEmitWithAwait ();
10130 public override Expression CreateExpressionTree (ResolveContext ec)
10132 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10133 return Expr.CreateExpressionTree (ec);
10136 protected override Expression DoResolve (ResolveContext ec)
10138 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10139 Expr = Expr.Resolve (ec);
10144 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10147 eclass = Expr.eclass;
10152 public override void Emit (EmitContext ec)
10154 using (ec.With (EmitContext.Options.CheckedScope, false))
10158 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10160 using (ec.With (EmitContext.Options.CheckedScope, false))
10161 Expr.EmitBranchable (ec, target, on_true);
10164 public override void FlowAnalysis (FlowAnalysisContext fc)
10166 Expr.FlowAnalysis (fc);
10169 protected override void CloneTo (CloneContext clonectx, Expression t)
10171 UnCheckedExpr target = (UnCheckedExpr) t;
10173 target.Expr = Expr.Clone (clonectx);
10176 public override object Accept (StructuralVisitor visitor)
10178 return visitor.Visit (this);
10183 /// An Element Access expression.
10185 /// During semantic analysis these are transformed into
10186 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10188 public class ElementAccess : Expression
10190 public Arguments Arguments;
10191 public Expression Expr;
10192 bool conditional_access_receiver;
10194 public ElementAccess (Expression e, Arguments args, Location loc)
10198 this.Arguments = args;
10201 public bool ConditionalAccess { get; set; }
10203 public override Location StartLocation {
10205 return Expr.StartLocation;
10209 public override bool ContainsEmitWithAwait ()
10211 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10215 // We perform some simple tests, and then to "split" the emit and store
10216 // code we create an instance of a different class, and return that.
10218 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10220 if (conditionalAccessReceiver)
10221 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10223 Expr = Expr.Resolve (ec);
10225 if (conditionalAccessReceiver)
10226 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10233 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10234 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10238 if (type.IsArray) {
10239 var aa = new ArrayAccess (this, loc) {
10240 ConditionalAccess = ConditionalAccess,
10243 if (conditionalAccessReceiver)
10244 aa.SetConditionalAccessReceiver ();
10249 if (type.IsPointer)
10250 return Expr.MakePointerAccess (ec, type, Arguments);
10252 FieldExpr fe = Expr as FieldExpr;
10254 var ff = fe.Spec as FixedFieldSpec;
10256 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10260 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10261 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10262 var indexer = new IndexerExpr (indexers, type, this) {
10263 ConditionalAccess = ConditionalAccess
10266 if (conditionalAccessReceiver)
10267 indexer.SetConditionalAccessReceiver ();
10272 Error_CannotApplyIndexing (ec, type, loc);
10277 public override Expression CreateExpressionTree (ResolveContext ec)
10279 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10280 Expr.CreateExpressionTree (ec));
10282 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10285 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10287 if (type != InternalType.ErrorType) {
10288 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10289 type.GetSignatureForError ());
10293 public override bool HasConditionalAccess ()
10295 return ConditionalAccess || Expr.HasConditionalAccess ();
10298 void ResolveConditionalAccessReceiver (ResolveContext rc)
10300 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10301 conditional_access_receiver = true;
10305 protected override Expression DoResolve (ResolveContext rc)
10307 ResolveConditionalAccessReceiver (rc);
10309 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10313 return expr.Resolve (rc);
10316 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10318 var res = CreateAccessExpression (ec, false);
10322 return res.ResolveLValue (ec, rhs);
10325 public override void Emit (EmitContext ec)
10327 throw new Exception ("Should never be reached");
10330 public override void FlowAnalysis (FlowAnalysisContext fc)
10332 Expr.FlowAnalysis (fc);
10334 Arguments.FlowAnalysis (fc);
10337 public override string GetSignatureForError ()
10339 return Expr.GetSignatureForError ();
10342 protected override void CloneTo (CloneContext clonectx, Expression t)
10344 ElementAccess target = (ElementAccess) t;
10346 target.Expr = Expr.Clone (clonectx);
10347 if (Arguments != null)
10348 target.Arguments = Arguments.Clone (clonectx);
10351 public override object Accept (StructuralVisitor visitor)
10353 return visitor.Visit (this);
10358 /// Implements array access
10360 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10362 // Points to our "data" repository
10366 LocalTemporary temp;
10368 bool? has_await_args;
10369 bool conditional_access_receiver;
10371 public ArrayAccess (ElementAccess ea_data, Location l)
10377 public bool ConditionalAccess { get; set; }
10379 public void AddressOf (EmitContext ec, AddressOp mode)
10381 var ac = (ArrayContainer) ea.Expr.Type;
10383 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10384 LoadInstanceAndArguments (ec, false, true);
10387 LoadInstanceAndArguments (ec, false, false);
10389 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10390 ec.Emit (OpCodes.Readonly);
10392 ec.EmitArrayAddress (ac);
10395 public override Expression CreateExpressionTree (ResolveContext ec)
10397 if (ConditionalAccess)
10398 Error_NullShortCircuitInsideExpressionTree (ec);
10400 return ea.CreateExpressionTree (ec);
10403 public override bool ContainsEmitWithAwait ()
10405 return ea.ContainsEmitWithAwait ();
10408 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10410 if (HasConditionalAccess ())
10411 Error_NullPropagatingLValue (ec);
10413 return DoResolve (ec);
10416 protected override Expression DoResolve (ResolveContext ec)
10418 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10420 ea.Arguments.Resolve (ec, out dynamic);
10422 var ac = ea.Expr.Type as ArrayContainer;
10423 int rank = ea.Arguments.Count;
10424 if (ac.Rank != rank) {
10425 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10426 rank.ToString (), ac.Rank.ToString ());
10431 if (type.IsPointer && !ec.IsUnsafe) {
10432 UnsafeError (ec, ea.Location);
10435 if (conditional_access_receiver)
10436 type = LiftMemberType (ec, type);
10438 foreach (Argument a in ea.Arguments) {
10439 var na = a as NamedArgument;
10441 ElementAccess.Error_NamedArgument (na, ec.Report);
10443 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10446 eclass = ExprClass.Variable;
10451 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10453 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10456 public override void FlowAnalysis (FlowAnalysisContext fc)
10458 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10460 ea.FlowAnalysis (fc);
10462 if (conditional_access_receiver)
10463 fc.DefiniteAssignment = da;
10466 public override bool HasConditionalAccess ()
10468 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10472 // Load the array arguments into the stack.
10474 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10476 if (prepareAwait) {
10477 ea.Expr = ea.Expr.EmitToField (ec);
10479 var ie = new InstanceEmitter (ea.Expr, false);
10480 ie.Emit (ec, ConditionalAccess);
10482 if (duplicateArguments) {
10483 ec.Emit (OpCodes.Dup);
10485 var copy = new LocalTemporary (ea.Expr.Type);
10491 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10492 if (dup_args != null)
10493 ea.Arguments = dup_args;
10496 public void Emit (EmitContext ec, bool leave_copy)
10499 ec.EmitLoadFromPtr (type);
10501 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10502 LoadInstanceAndArguments (ec, false, true);
10505 if (conditional_access_receiver)
10506 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10508 var ac = (ArrayContainer) ea.Expr.Type;
10509 LoadInstanceAndArguments (ec, false, false);
10510 ec.EmitArrayLoad (ac);
10512 if (conditional_access_receiver)
10513 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10517 ec.Emit (OpCodes.Dup);
10518 temp = new LocalTemporary (this.type);
10523 public override void Emit (EmitContext ec)
10528 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10530 var ac = (ArrayContainer) ea.Expr.Type;
10531 TypeSpec t = source.Type;
10533 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10536 // When we are dealing with a struct, get the address of it to avoid value copy
10537 // Same cannot be done for reference type because array covariance and the
10538 // check in ldelema requires to specify the type of array element stored at the index
10540 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10541 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10543 if (has_await_args.Value) {
10544 if (source.ContainsEmitWithAwait ()) {
10545 source = source.EmitToField (ec);
10546 isCompound = false;
10550 LoadInstanceAndArguments (ec, isCompound, false);
10555 ec.EmitArrayAddress (ac);
10558 ec.Emit (OpCodes.Dup);
10562 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10564 if (has_await_args.Value) {
10565 if (source.ContainsEmitWithAwait ())
10566 source = source.EmitToField (ec);
10568 LoadInstanceAndArguments (ec, false, false);
10575 var lt = ea.Expr as LocalTemporary;
10581 ec.Emit (OpCodes.Dup);
10582 temp = new LocalTemporary (this.type);
10587 ec.EmitStoreFromPtr (t);
10589 ec.EmitArrayStore (ac);
10592 if (temp != null) {
10598 public override Expression EmitToField (EmitContext ec)
10601 // Have to be specialized for arrays to get access to
10602 // underlying element. Instead of another result copy we
10603 // need direct access to element
10607 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10609 ea.Expr = ea.Expr.EmitToField (ec);
10610 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10614 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10616 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10619 public override SLE.Expression MakeExpression (BuilderContext ctx)
10621 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10624 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10626 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10627 return Arguments.MakeExpression (ea.Arguments, ctx);
10631 public void SetConditionalAccessReceiver ()
10633 conditional_access_receiver = true;
10638 // Indexer access expression
10640 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10642 IList<MemberSpec> indexers;
10643 Arguments arguments;
10644 TypeSpec queried_type;
10646 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10647 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10651 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10654 this.indexers = indexers;
10655 this.queried_type = queriedType;
10656 this.InstanceExpression = instance;
10657 this.arguments = args;
10662 protected override Arguments Arguments {
10671 protected override TypeSpec DeclaringType {
10673 return best_candidate.DeclaringType;
10677 public override bool IsInstance {
10683 public override bool IsStatic {
10689 public override string KindName {
10690 get { return "indexer"; }
10693 public override string Name {
10701 public override bool ContainsEmitWithAwait ()
10703 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10706 public override Expression CreateExpressionTree (ResolveContext ec)
10708 if (ConditionalAccess) {
10709 Error_NullShortCircuitInsideExpressionTree (ec);
10712 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10713 InstanceExpression.CreateExpressionTree (ec),
10714 new TypeOfMethod (Getter, loc));
10716 return CreateExpressionFactoryCall (ec, "Call", args);
10719 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10721 LocalTemporary await_source_arg = null;
10724 emitting_compound_assignment = true;
10725 if (source is DynamicExpressionStatement) {
10730 emitting_compound_assignment = false;
10732 if (has_await_arguments) {
10733 await_source_arg = new LocalTemporary (Type);
10734 await_source_arg.Store (ec);
10736 arguments.Add (new Argument (await_source_arg));
10739 temp = await_source_arg;
10742 has_await_arguments = false;
10747 ec.Emit (OpCodes.Dup);
10748 temp = new LocalTemporary (Type);
10754 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10755 source = source.EmitToField (ec);
10757 temp = new LocalTemporary (Type);
10764 arguments.Add (new Argument (source));
10767 var call = new CallEmitter ();
10768 call.InstanceExpression = InstanceExpression;
10769 if (arguments == null)
10770 call.InstanceExpressionOnStack = true;
10772 call.Emit (ec, Setter, arguments, loc);
10774 if (temp != null) {
10777 } else if (leave_copy) {
10781 if (await_source_arg != null) {
10782 await_source_arg.Release (ec);
10786 public override void FlowAnalysis (FlowAnalysisContext fc)
10788 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10790 base.FlowAnalysis (fc);
10791 arguments.FlowAnalysis (fc);
10793 if (conditional_access_receiver)
10794 fc.DefiniteAssignment = da;
10797 public override string GetSignatureForError ()
10799 return best_candidate.GetSignatureForError ();
10802 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10805 throw new NotSupportedException ();
10807 var value = new[] { source.MakeExpression (ctx) };
10808 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10809 return SLE.Expression.Block (
10810 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10815 public override SLE.Expression MakeExpression (BuilderContext ctx)
10818 return base.MakeExpression (ctx);
10820 var args = Arguments.MakeExpression (arguments, ctx);
10821 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10825 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10827 if (best_candidate != null)
10830 eclass = ExprClass.IndexerAccess;
10833 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
10834 arguments.Resolve (rc, out dynamic);
10837 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10840 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10841 res.BaseMembersProvider = this;
10842 res.InstanceQualifier = this;
10844 // TODO: Do I need 2 argument sets?
10845 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10846 if (best_candidate != null)
10847 type = res.BestCandidateReturnType;
10848 else if (!res.BestCandidateIsDynamic)
10853 // It has dynamic arguments
10856 Arguments args = new Arguments (arguments.Count + 1);
10858 rc.Report.Error (1972, loc,
10859 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10861 args.Add (new Argument (InstanceExpression));
10863 args.AddRange (arguments);
10865 best_candidate = null;
10866 return new DynamicIndexBinder (args, loc);
10870 // Try to avoid resolving left expression again
10872 if (right_side != null)
10873 ResolveInstanceExpression (rc, right_side);
10878 protected override void CloneTo (CloneContext clonectx, Expression t)
10880 IndexerExpr target = (IndexerExpr) t;
10882 if (arguments != null)
10883 target.arguments = arguments.Clone (clonectx);
10886 public void SetConditionalAccessReceiver ()
10888 conditional_access_receiver = true;
10891 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10893 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10896 #region IBaseMembersProvider Members
10898 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10900 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10903 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10905 if (queried_type == member.DeclaringType)
10908 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10909 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10912 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10921 // A base access expression
10923 public class BaseThis : This
10925 public BaseThis (Location loc)
10930 public BaseThis (TypeSpec type, Location loc)
10934 eclass = ExprClass.Variable;
10939 public override string Name {
10947 public override Expression CreateExpressionTree (ResolveContext ec)
10949 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10950 return base.CreateExpressionTree (ec);
10953 public override void Emit (EmitContext ec)
10957 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10958 var context_type = ec.CurrentType;
10959 ec.Emit (OpCodes.Ldobj, context_type);
10960 ec.Emit (OpCodes.Box, context_type);
10964 protected override void Error_ThisNotAvailable (ResolveContext ec)
10967 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10969 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10973 public override void ResolveBase (ResolveContext ec)
10975 base.ResolveBase (ec);
10976 type = ec.CurrentType.BaseType;
10979 public override object Accept (StructuralVisitor visitor)
10981 return visitor.Visit (this);
10986 /// This class exists solely to pass the Type around and to be a dummy
10987 /// that can be passed to the conversion functions (this is used by
10988 /// foreach implementation to typecast the object return value from
10989 /// get_Current into the proper type. All code has been generated and
10990 /// we only care about the side effect conversions to be performed
10992 /// This is also now used as a placeholder where a no-action expression
10993 /// is needed (the `New' class).
10995 public class EmptyExpression : Expression
10997 sealed class OutAccessExpression : EmptyExpression
10999 public OutAccessExpression (TypeSpec t)
11004 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11006 rc.Report.Error (206, right_side.Location,
11007 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11013 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11014 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11015 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11016 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11017 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11018 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11019 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11020 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11022 public EmptyExpression (TypeSpec t)
11025 eclass = ExprClass.Value;
11026 loc = Location.Null;
11029 protected override void CloneTo (CloneContext clonectx, Expression target)
11033 public override bool ContainsEmitWithAwait ()
11038 public override Expression CreateExpressionTree (ResolveContext ec)
11040 throw new NotSupportedException ("ET");
11043 protected override Expression DoResolve (ResolveContext ec)
11048 public override void Emit (EmitContext ec)
11050 // nothing, as we only exist to not do anything.
11053 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11057 public override void EmitSideEffect (EmitContext ec)
11061 public override object Accept (StructuralVisitor visitor)
11063 return visitor.Visit (this);
11067 sealed class EmptyAwaitExpression : EmptyExpression
11069 public EmptyAwaitExpression (TypeSpec type)
11074 public override bool ContainsEmitWithAwait ()
11081 // Empty statement expression
11083 public sealed class EmptyExpressionStatement : ExpressionStatement
11085 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11087 private EmptyExpressionStatement ()
11089 loc = Location.Null;
11092 public override bool ContainsEmitWithAwait ()
11097 public override Expression CreateExpressionTree (ResolveContext ec)
11102 public override void EmitStatement (EmitContext ec)
11107 protected override Expression DoResolve (ResolveContext ec)
11109 eclass = ExprClass.Value;
11110 type = ec.BuiltinTypes.Object;
11114 public override void Emit (EmitContext ec)
11119 public override object Accept (StructuralVisitor visitor)
11121 return visitor.Visit (this);
11125 public class ErrorExpression : EmptyExpression
11127 public static readonly ErrorExpression Instance = new ErrorExpression ();
11129 private ErrorExpression ()
11130 : base (InternalType.ErrorType)
11134 public override Expression CreateExpressionTree (ResolveContext ec)
11139 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11144 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11148 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11152 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11156 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11160 public override object Accept (StructuralVisitor visitor)
11162 return visitor.Visit (this);
11166 public class UserCast : Expression {
11170 public UserCast (MethodSpec method, Expression source, Location l)
11172 if (source == null)
11173 throw new ArgumentNullException ("source");
11175 this.method = method;
11176 this.source = source;
11177 type = method.ReturnType;
11181 public Expression Source {
11190 public override bool ContainsEmitWithAwait ()
11192 return source.ContainsEmitWithAwait ();
11195 public override Expression CreateExpressionTree (ResolveContext ec)
11197 Arguments args = new Arguments (3);
11198 args.Add (new Argument (source.CreateExpressionTree (ec)));
11199 args.Add (new Argument (new TypeOf (type, loc)));
11200 args.Add (new Argument (new TypeOfMethod (method, loc)));
11201 return CreateExpressionFactoryCall (ec, "Convert", args);
11204 protected override Expression DoResolve (ResolveContext ec)
11206 method.CheckObsoleteness (ec, source.Location);
11208 eclass = ExprClass.Value;
11212 public override void Emit (EmitContext ec)
11215 ec.MarkCallEntry (loc);
11216 ec.Emit (OpCodes.Call, method);
11219 public override void FlowAnalysis (FlowAnalysisContext fc)
11221 source.FlowAnalysis (fc);
11224 public override string GetSignatureForError ()
11226 return TypeManager.CSharpSignature (method);
11229 public override SLE.Expression MakeExpression (BuilderContext ctx)
11232 return base.MakeExpression (ctx);
11234 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11240 // Holds additional type specifiers like ?, *, []
11242 public class ComposedTypeSpecifier
11244 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11246 public readonly int Dimension;
11247 public readonly Location Location;
11249 public ComposedTypeSpecifier (int specifier, Location loc)
11251 this.Dimension = specifier;
11252 this.Location = loc;
11256 public bool IsNullable {
11258 return Dimension == -1;
11262 public bool IsPointer {
11264 return Dimension == -2;
11268 public ComposedTypeSpecifier Next { get; set; }
11272 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11274 return new ComposedTypeSpecifier (dimension, loc);
11277 public static ComposedTypeSpecifier CreateNullable (Location loc)
11279 return new ComposedTypeSpecifier (-1, loc);
11282 public static ComposedTypeSpecifier CreatePointer (Location loc)
11284 return new ComposedTypeSpecifier (-2, loc);
11287 public string GetSignatureForError ()
11292 ArrayContainer.GetPostfixSignature (Dimension);
11294 return Next != null ? s + Next.GetSignatureForError () : s;
11299 // This class is used to "construct" the type during a typecast
11300 // operation. Since the Type.GetType class in .NET can parse
11301 // the type specification, we just use this to construct the type
11302 // one bit at a time.
11304 public class ComposedCast : TypeExpr {
11305 FullNamedExpression left;
11306 ComposedTypeSpecifier spec;
11308 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11311 throw new ArgumentNullException ("spec");
11315 this.loc = left.Location;
11318 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11320 type = left.ResolveAsType (ec);
11324 eclass = ExprClass.Type;
11326 var single_spec = spec;
11328 if (single_spec.IsNullable) {
11329 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11333 single_spec = single_spec.Next;
11334 } else if (single_spec.IsPointer) {
11336 // Declared fields cannot have unmanaged check done before all types are defined
11338 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11341 if (!ec.IsUnsafe) {
11342 UnsafeError (ec.Module.Compiler.Report, loc);
11346 type = PointerContainer.MakeType (ec.Module, type);
11347 single_spec = single_spec.Next;
11348 } while (single_spec != null && single_spec.IsPointer);
11351 if (single_spec != null && single_spec.Dimension > 0) {
11352 if (type.IsSpecialRuntimeType) {
11353 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11354 } else if (type.IsStatic) {
11355 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11356 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11357 type.GetSignatureForError ());
11359 MakeArray (ec.Module, single_spec);
11366 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11368 if (spec.Next != null)
11369 MakeArray (module, spec.Next);
11371 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11374 public override string GetSignatureForError ()
11376 return left.GetSignatureForError () + spec.GetSignatureForError ();
11379 public override object Accept (StructuralVisitor visitor)
11381 return visitor.Visit (this);
11385 class FixedBufferPtr : Expression
11387 readonly Expression array;
11389 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11391 this.type = array_type;
11392 this.array = array;
11396 public override bool ContainsEmitWithAwait ()
11398 throw new NotImplementedException ();
11401 public override Expression CreateExpressionTree (ResolveContext ec)
11403 Error_PointerInsideExpressionTree (ec);
11407 public override void Emit(EmitContext ec)
11412 protected override Expression DoResolve (ResolveContext ec)
11414 type = PointerContainer.MakeType (ec.Module, type);
11415 eclass = ExprClass.Value;
11422 // This class is used to represent the address of an array, used
11423 // only by the Fixed statement, this generates "&a [0]" construct
11424 // for fixed (char *pa = a)
11426 class ArrayPtr : FixedBufferPtr
11428 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11429 base (array, array_type, l)
11433 public override void Emit (EmitContext ec)
11438 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11443 // Encapsulates a conversion rules required for array indexes
11445 public class ArrayIndexCast : TypeCast
11447 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11448 : base (expr, returnType)
11450 if (expr.Type == returnType) // int -> int
11451 throw new ArgumentException ("unnecessary array index conversion");
11454 public override Expression CreateExpressionTree (ResolveContext ec)
11456 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11457 return base.CreateExpressionTree (ec);
11461 public override void Emit (EmitContext ec)
11465 switch (child.Type.BuiltinType) {
11466 case BuiltinTypeSpec.Type.UInt:
11467 ec.Emit (OpCodes.Conv_U);
11469 case BuiltinTypeSpec.Type.Long:
11470 ec.Emit (OpCodes.Conv_Ovf_I);
11472 case BuiltinTypeSpec.Type.ULong:
11473 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11476 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11482 // Implements the `stackalloc' keyword
11484 public class StackAlloc : Expression {
11489 public StackAlloc (Expression type, Expression count, Location l)
11492 this.count = count;
11496 public Expression TypeExpression {
11502 public Expression CountExpression {
11508 public override bool ContainsEmitWithAwait ()
11513 public override Expression CreateExpressionTree (ResolveContext ec)
11515 throw new NotSupportedException ("ET");
11518 protected override Expression DoResolve (ResolveContext ec)
11520 count = count.Resolve (ec);
11524 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11525 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11530 Constant c = count as Constant;
11531 if (c != null && c.IsNegative) {
11532 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11535 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11536 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11539 otype = texpr.ResolveAsType (ec);
11543 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11546 type = PointerContainer.MakeType (ec.Module, otype);
11547 eclass = ExprClass.Value;
11552 public override void Emit (EmitContext ec)
11554 int size = BuiltinTypeSpec.GetSize (otype);
11559 ec.Emit (OpCodes.Sizeof, otype);
11563 ec.Emit (OpCodes.Mul_Ovf_Un);
11564 ec.Emit (OpCodes.Localloc);
11567 protected override void CloneTo (CloneContext clonectx, Expression t)
11569 StackAlloc target = (StackAlloc) t;
11570 target.count = count.Clone (clonectx);
11571 target.texpr = texpr.Clone (clonectx);
11574 public override object Accept (StructuralVisitor visitor)
11576 return visitor.Visit (this);
11581 // An object initializer expression
11583 public class ElementInitializer : Assign
11585 public readonly string Name;
11587 public ElementInitializer (string name, Expression initializer, Location loc)
11588 : base (null, initializer, loc)
11593 public bool IsDictionaryInitializer {
11595 return Name == null;
11599 protected override void CloneTo (CloneContext clonectx, Expression t)
11601 ElementInitializer target = (ElementInitializer) t;
11602 target.source = source.Clone (clonectx);
11605 public override Expression CreateExpressionTree (ResolveContext ec)
11607 Arguments args = new Arguments (2);
11608 FieldExpr fe = target as FieldExpr;
11610 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11612 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11615 Expression arg_expr;
11616 var cinit = source as CollectionOrObjectInitializers;
11617 if (cinit == null) {
11619 arg_expr = source.CreateExpressionTree (ec);
11621 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11622 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11625 args.Add (new Argument (arg_expr));
11626 return CreateExpressionFactoryCall (ec, mname, args);
11629 protected override Expression DoResolve (ResolveContext ec)
11631 if (source == null)
11632 return EmptyExpressionStatement.Instance;
11634 if (!ResolveElement (ec))
11637 if (source is CollectionOrObjectInitializers) {
11638 target = target.Resolve (ec);
11639 if (target == null)
11642 Expression previous = ec.CurrentInitializerVariable;
11643 ec.CurrentInitializerVariable = target;
11644 source = source.Resolve (ec);
11645 ec.CurrentInitializerVariable = previous;
11646 if (source == null)
11649 eclass = source.eclass;
11650 type = source.Type;
11655 return base.DoResolve (ec);
11658 public override void EmitStatement (EmitContext ec)
11660 if (source is CollectionOrObjectInitializers)
11663 base.EmitStatement (ec);
11666 protected virtual bool ResolveElement (ResolveContext rc)
11668 var t = rc.CurrentInitializerVariable.Type;
11669 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11670 Arguments args = new Arguments (1);
11671 args.Add (new Argument (rc.CurrentInitializerVariable));
11672 target = new DynamicMemberBinder (Name, args, loc);
11675 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11676 if (member == null) {
11677 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11679 if (member != null) {
11680 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11681 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11686 if (member == null) {
11687 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11691 var me = member as MemberExpr;
11692 if (me is EventExpr) {
11693 me = me.ResolveMemberAccess (rc, null, null);
11694 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11695 rc.Report.Error (1913, loc,
11696 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11697 member.GetSignatureForError ());
11703 rc.Report.Error (1914, loc,
11704 "Static field or property `{0}' cannot be assigned in an object initializer",
11705 me.GetSignatureForError ());
11709 me.InstanceExpression = rc.CurrentInitializerVariable;
11717 // A collection initializer expression
11719 class CollectionElementInitializer : Invocation
11721 public class ElementInitializerArgument : Argument
11723 public ElementInitializerArgument (Expression e)
11729 sealed class AddMemberAccess : MemberAccess
11731 public AddMemberAccess (Expression expr, Location loc)
11732 : base (expr, "Add", loc)
11736 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11738 if (TypeManager.HasElementType (type))
11741 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11745 public CollectionElementInitializer (Expression argument)
11746 : base (null, new Arguments (1))
11748 base.arguments.Add (new ElementInitializerArgument (argument));
11749 this.loc = argument.Location;
11752 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11753 : base (null, new Arguments (arguments.Count))
11755 foreach (Expression e in arguments)
11756 base.arguments.Add (new ElementInitializerArgument (e));
11761 public CollectionElementInitializer (Location loc)
11762 : base (null, null)
11767 public override Expression CreateExpressionTree (ResolveContext ec)
11769 Arguments args = new Arguments (2);
11770 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11772 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11773 foreach (Argument a in arguments) {
11774 if (a.ArgType == Argument.AType.ExtensionType) {
11775 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11778 expr_initializers.Add (a.CreateExpressionTree (ec));
11781 args.Add (new Argument (new ArrayCreation (
11782 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11783 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11786 protected override void CloneTo (CloneContext clonectx, Expression t)
11788 CollectionElementInitializer target = (CollectionElementInitializer) t;
11789 if (arguments != null)
11790 target.arguments = arguments.Clone (clonectx);
11793 protected override Expression DoResolve (ResolveContext ec)
11795 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11797 return base.DoResolve (ec);
11801 class DictionaryElementInitializer : ElementInitializer
11803 readonly Arguments args;
11805 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11806 : base (null, initializer, loc)
11808 this.args = arguments;
11811 public override Expression CreateExpressionTree (ResolveContext ec)
11813 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11817 protected override bool ResolveElement (ResolveContext rc)
11819 var init = rc.CurrentInitializerVariable;
11820 var type = init.Type;
11822 if (type.IsArray) {
11823 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11827 if (type.IsPointer) {
11828 target = init.MakePointerAccess (rc, type, args);
11832 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11833 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11834 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11838 target = new IndexerExpr (indexers, type, init, args, loc);
11844 // A block of object or collection initializers
11846 public class CollectionOrObjectInitializers : ExpressionStatement
11848 IList<Expression> initializers;
11849 bool is_collection_initialization;
11851 public CollectionOrObjectInitializers (Location loc)
11852 : this (new Expression[0], loc)
11856 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11858 this.initializers = initializers;
11862 public IList<Expression> Initializers {
11864 return initializers;
11868 public bool IsEmpty {
11870 return initializers.Count == 0;
11874 public bool IsCollectionInitializer {
11876 return is_collection_initialization;
11880 protected override void CloneTo (CloneContext clonectx, Expression target)
11882 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11884 t.initializers = new List<Expression> (initializers.Count);
11885 foreach (var e in initializers)
11886 t.initializers.Add (e.Clone (clonectx));
11889 public override bool ContainsEmitWithAwait ()
11891 foreach (var e in initializers) {
11892 if (e.ContainsEmitWithAwait ())
11899 public override Expression CreateExpressionTree (ResolveContext ec)
11901 return CreateExpressionTree (ec, false);
11904 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11906 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11907 foreach (Expression e in initializers) {
11908 Expression expr = e.CreateExpressionTree (ec);
11910 expr_initializers.Add (expr);
11914 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11916 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11919 protected override Expression DoResolve (ResolveContext ec)
11921 List<string> element_names = null;
11922 for (int i = 0; i < initializers.Count; ++i) {
11923 Expression initializer = initializers [i];
11924 ElementInitializer element_initializer = initializer as ElementInitializer;
11927 if (element_initializer != null) {
11928 element_names = new List<string> (initializers.Count);
11929 if (!element_initializer.IsDictionaryInitializer)
11930 element_names.Add (element_initializer.Name);
11931 } else if (initializer is CompletingExpression) {
11932 initializer.Resolve (ec);
11933 throw new InternalErrorException ("This line should never be reached");
11935 var t = ec.CurrentInitializerVariable.Type;
11936 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11937 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11938 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11939 "object initializer because type `{1}' does not implement `{2}' interface",
11940 ec.CurrentInitializerVariable.GetSignatureForError (),
11941 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11942 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11945 is_collection_initialization = true;
11948 if (is_collection_initialization != (element_initializer == null)) {
11949 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11950 is_collection_initialization ? "collection initializer" : "object initializer");
11954 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11955 if (element_names.Contains (element_initializer.Name)) {
11956 ec.Report.Error (1912, element_initializer.Location,
11957 "An object initializer includes more than one member `{0}' initialization",
11958 element_initializer.Name);
11960 element_names.Add (element_initializer.Name);
11965 Expression e = initializer.Resolve (ec);
11966 if (e == EmptyExpressionStatement.Instance)
11967 initializers.RemoveAt (i--);
11969 initializers [i] = e;
11972 type = ec.CurrentInitializerVariable.Type;
11973 if (is_collection_initialization) {
11974 if (TypeManager.HasElementType (type)) {
11975 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11976 type.GetSignatureForError ());
11980 eclass = ExprClass.Variable;
11984 public override void Emit (EmitContext ec)
11986 EmitStatement (ec);
11989 public override void EmitStatement (EmitContext ec)
11991 foreach (ExpressionStatement e in initializers) {
11992 // TODO: need location region
11993 ec.Mark (e.Location);
11994 e.EmitStatement (ec);
11998 public override void FlowAnalysis (FlowAnalysisContext fc)
12000 foreach (var initializer in initializers) {
12001 if (initializer != null)
12002 initializer.FlowAnalysis (fc);
12008 // New expression with element/object initializers
12010 public class NewInitialize : New
12013 // This class serves as a proxy for variable initializer target instances.
12014 // A real variable is assigned later when we resolve left side of an
12017 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12019 NewInitialize new_instance;
12021 public InitializerTargetExpression (NewInitialize newInstance)
12023 this.type = newInstance.type;
12024 this.loc = newInstance.loc;
12025 this.eclass = newInstance.eclass;
12026 this.new_instance = newInstance;
12029 public override bool ContainsEmitWithAwait ()
12034 public override Expression CreateExpressionTree (ResolveContext ec)
12036 // Should not be reached
12037 throw new NotSupportedException ("ET");
12040 protected override Expression DoResolve (ResolveContext ec)
12045 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12050 public override void Emit (EmitContext ec)
12052 Expression e = (Expression) new_instance.instance;
12056 public override Expression EmitToField (EmitContext ec)
12058 return (Expression) new_instance.instance;
12061 #region IMemoryLocation Members
12063 public void AddressOf (EmitContext ec, AddressOp mode)
12065 new_instance.instance.AddressOf (ec, mode);
12071 CollectionOrObjectInitializers initializers;
12072 IMemoryLocation instance;
12073 DynamicExpressionStatement dynamic;
12075 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12076 : base (requested_type, arguments, l)
12078 this.initializers = initializers;
12081 public CollectionOrObjectInitializers Initializers {
12083 return initializers;
12087 protected override void CloneTo (CloneContext clonectx, Expression t)
12089 base.CloneTo (clonectx, t);
12091 NewInitialize target = (NewInitialize) t;
12092 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12095 public override bool ContainsEmitWithAwait ()
12097 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12100 public override Expression CreateExpressionTree (ResolveContext ec)
12102 Arguments args = new Arguments (2);
12103 args.Add (new Argument (base.CreateExpressionTree (ec)));
12104 if (!initializers.IsEmpty)
12105 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12107 return CreateExpressionFactoryCall (ec,
12108 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12112 protected override Expression DoResolve (ResolveContext ec)
12114 Expression e = base.DoResolve (ec);
12118 if (type.IsDelegate) {
12119 ec.Report.Error (1958, Initializers.Location,
12120 "Object and collection initializers cannot be used to instantiate a delegate");
12123 Expression previous = ec.CurrentInitializerVariable;
12124 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12125 initializers.Resolve (ec);
12126 ec.CurrentInitializerVariable = previous;
12128 dynamic = e as DynamicExpressionStatement;
12129 if (dynamic != null)
12135 public override void Emit (EmitContext ec)
12137 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12138 var fe = ec.GetTemporaryField (type);
12140 if (!Emit (ec, fe))
12149 public override bool Emit (EmitContext ec, IMemoryLocation target)
12152 // Expression is initialized into temporary target then moved
12153 // to real one for atomicity
12155 IMemoryLocation temp_target = target;
12157 LocalTemporary temp = null;
12158 bool by_ref = false;
12159 if (!initializers.IsEmpty) {
12160 temp_target = target as LocalTemporary;
12161 if (temp_target == null)
12162 temp_target = target as StackFieldExpr;
12164 if (temp_target == null) {
12165 var vr = target as VariableReference;
12166 if (vr != null && vr.IsRef) {
12172 if (temp_target == null)
12173 temp_target = temp = new LocalTemporary (type);
12176 bool left_on_stack;
12177 if (dynamic != null) {
12179 left_on_stack = true;
12181 left_on_stack = base.Emit (ec, temp_target);
12184 if (initializers.IsEmpty)
12185 return left_on_stack;
12187 StackFieldExpr sf = null;
12189 // Move a new instance (reference-type) to local temporary variable
12190 if (left_on_stack) {
12192 temp_target = temp = new LocalTemporary (type);
12198 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12200 throw new NotImplementedException ();
12202 sf = ec.GetTemporaryField (type);
12203 sf.EmitAssign (ec, temp, false, false);
12206 left_on_stack = false;
12210 instance = temp_target;
12212 initializers.Emit (ec);
12214 ((Expression)temp_target).Emit (ec);
12220 sf.IsAvailableForReuse = true;
12225 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12227 instance = base.EmitAddressOf (ec, Mode);
12229 if (!initializers.IsEmpty)
12230 initializers.Emit (ec);
12235 public override void FlowAnalysis (FlowAnalysisContext fc)
12237 base.FlowAnalysis (fc);
12238 initializers.FlowAnalysis (fc);
12241 public override object Accept (StructuralVisitor visitor)
12243 return visitor.Visit (this);
12247 public class NewAnonymousType : New
12249 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12251 List<AnonymousTypeParameter> parameters;
12252 readonly TypeContainer parent;
12253 AnonymousTypeClass anonymous_type;
12255 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12256 : base (null, null, loc)
12258 this.parameters = parameters;
12259 this.parent = parent;
12262 public List<AnonymousTypeParameter> Parameters {
12264 return this.parameters;
12268 protected override void CloneTo (CloneContext clonectx, Expression target)
12270 if (parameters == null)
12273 NewAnonymousType t = (NewAnonymousType) target;
12274 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12275 foreach (AnonymousTypeParameter atp in parameters)
12276 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12279 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12281 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12285 type = AnonymousTypeClass.Create (parent, parameters, loc);
12289 int errors = ec.Report.Errors;
12290 type.CreateContainer ();
12291 type.DefineContainer ();
12293 if ((ec.Report.Errors - errors) == 0) {
12294 parent.Module.AddAnonymousType (type);
12295 type.PrepareEmit ();
12301 public override Expression CreateExpressionTree (ResolveContext ec)
12303 if (parameters == null)
12304 return base.CreateExpressionTree (ec);
12306 var init = new ArrayInitializer (parameters.Count, loc);
12307 foreach (var m in anonymous_type.Members) {
12308 var p = m as Property;
12310 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12313 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12314 foreach (Argument a in arguments)
12315 ctor_args.Add (a.CreateExpressionTree (ec));
12317 Arguments args = new Arguments (3);
12318 args.Add (new Argument (new TypeOfMethod (method, loc)));
12319 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12320 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12322 return CreateExpressionFactoryCall (ec, "New", args);
12325 protected override Expression DoResolve (ResolveContext ec)
12327 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12328 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12332 if (parameters == null) {
12333 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12334 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12335 return base.DoResolve (ec);
12338 bool error = false;
12339 arguments = new Arguments (parameters.Count);
12340 var t_args = new TypeSpec [parameters.Count];
12341 for (int i = 0; i < parameters.Count; ++i) {
12342 Expression e = parameters [i].Resolve (ec);
12348 arguments.Add (new Argument (e));
12349 t_args [i] = e.Type;
12355 anonymous_type = CreateAnonymousType (ec, parameters);
12356 if (anonymous_type == null)
12359 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12360 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12361 eclass = ExprClass.Value;
12365 public override object Accept (StructuralVisitor visitor)
12367 return visitor.Visit (this);
12371 public class AnonymousTypeParameter : ShimExpression
12373 public readonly string Name;
12375 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12376 : base (initializer)
12382 public AnonymousTypeParameter (Parameter parameter)
12383 : base (new SimpleName (parameter.Name, parameter.Location))
12385 this.Name = parameter.Name;
12386 this.loc = parameter.Location;
12389 public override bool Equals (object o)
12391 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12392 return other != null && Name == other.Name;
12395 public override int GetHashCode ()
12397 return Name.GetHashCode ();
12400 protected override Expression DoResolve (ResolveContext ec)
12402 Expression e = expr.Resolve (ec);
12406 if (e.eclass == ExprClass.MethodGroup) {
12407 Error_InvalidInitializer (ec, e.ExprClassName);
12412 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12413 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12420 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12422 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12423 Name, initializer);
12427 public class CatchFilterExpression : BooleanExpression
12429 public CatchFilterExpression (Expression expr, Location loc)
12436 public class InterpolatedString : Expression
12438 readonly StringLiteral start, end;
12439 List<Expression> interpolations;
12440 Arguments arguments;
12442 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12444 this.start = start;
12446 this.interpolations = interpolations;
12447 loc = start.Location;
12450 protected override void CloneTo (CloneContext clonectx, Expression t)
12452 InterpolatedString target = (InterpolatedString) t;
12454 if (interpolations != null) {
12455 target.interpolations = new List<Expression> ();
12456 foreach (var interpolation in interpolations) {
12457 target.interpolations.Add (interpolation.Clone (clonectx));
12462 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12464 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12465 if (factory == null)
12468 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12469 var res = new Invocation (ma, arguments).Resolve (rc);
12470 if (res != null && res.Type != type)
12471 res = Convert.ExplicitConversion (rc, res, type, loc);
12476 public override bool ContainsEmitWithAwait ()
12478 if (interpolations == null)
12481 foreach (var expr in interpolations) {
12482 if (expr.ContainsEmitWithAwait ())
12489 public override Expression CreateExpressionTree (ResolveContext rc)
12491 var best = ResolveBestFormatOverload (rc);
12495 Expression instance = new NullLiteral (loc);
12496 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12497 return CreateExpressionFactoryCall (rc, "Call", args);
12500 protected override Expression DoResolve (ResolveContext rc)
12504 if (interpolations == null) {
12506 arguments = new Arguments (1);
12508 arguments = new Arguments (interpolations.Count);
12510 var sb = new StringBuilder (start.Value);
12511 for (int i = 0; i < interpolations.Count; ++i) {
12513 sb.Append ('{').Append (i / 2);
12514 var isi = (InterpolatedStringInsert)interpolations [i];
12515 if (isi.Alignment != null) {
12517 var value = isi.ResolveAligment (rc);
12519 sb.Append (value.Value);
12522 if (isi.Format != null) {
12524 sb.Append (isi.Format);
12528 arguments.Add (new Argument (isi.Resolve (rc)));
12530 sb.Append (((StringLiteral)interpolations [i]).Value);
12534 sb.Append (end.Value);
12535 str = sb.ToString ();
12538 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12540 eclass = ExprClass.Value;
12541 type = rc.BuiltinTypes.String;
12545 public override void Emit (EmitContext ec)
12547 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12548 if (interpolations == null) {
12549 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12550 if (str != start.Value)
12551 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12558 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12562 var ca = new CallEmitter ();
12563 ca.Emit (ec, best, arguments, loc);
12566 public override void FlowAnalysis (FlowAnalysisContext fc)
12568 if (interpolations != null) {
12569 foreach (var expr in interpolations) {
12570 expr.FlowAnalysis (fc);
12575 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12577 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12578 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12579 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12583 public class InterpolatedStringInsert : CompositeExpression
12585 public InterpolatedStringInsert (Expression expr)
12590 public Expression Alignment { get; set; }
12591 public string Format { get; set; }
12593 protected override void CloneTo (CloneContext clonectx, Expression t)
12595 var target = (InterpolatedStringInsert)t;
12596 target.expr = expr.Clone (clonectx);
12597 if (Alignment != null)
12598 target.Alignment = Alignment.Clone (clonectx);
12601 protected override Expression DoResolve (ResolveContext rc)
12603 var expr = base.DoResolve (rc);
12608 // For better error reporting, assumes the built-in implementation uses object
12611 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12614 public override void FlowAnalysis (FlowAnalysisContext fc)
12616 Child.FlowAnalysis (fc);
12619 public int? ResolveAligment (ResolveContext rc)
12621 var c = Alignment.ResolveLabelConstant (rc);
12625 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12629 var value = (int) c.GetValueAsLong ();
12630 if (value > 32767 || value < -32767) {
12631 rc.Report.Warning (8094, 1, Alignment.Location,
12632 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");