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;
19 using MetaType = IKVM.Reflection.Type;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using MetaType = System.Type;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // This is an user operator expression, automatically created during
34 public class UserOperatorCall : Expression {
35 protected readonly Arguments arguments;
36 protected readonly MethodSpec oper;
37 readonly Func<ResolveContext, Expression, Expression> expr_tree;
39 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
42 this.arguments = args;
43 this.expr_tree = expr_tree;
45 type = oper.ReturnType;
46 eclass = ExprClass.Value;
50 public override bool ContainsEmitWithAwait ()
52 return arguments.ContainsEmitWithAwait ();
55 public override Expression CreateExpressionTree (ResolveContext ec)
57 if (expr_tree != null)
58 return expr_tree (ec, new TypeOfMethod (oper, loc));
60 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
61 new NullLiteral (loc),
62 new TypeOfMethod (oper, loc));
64 return CreateExpressionFactoryCall (ec, "Call", args);
67 protected override void CloneTo (CloneContext context, Expression target)
72 protected override Expression DoResolve (ResolveContext ec)
75 // We are born fully resolved
80 public override void Emit (EmitContext ec)
82 var call = new CallEmitter ();
83 call.Emit (ec, oper, arguments, loc);
86 public override void FlowAnalysis (FlowAnalysisContext fc)
88 arguments.FlowAnalysis (fc);
91 public override SLE.Expression MakeExpression (BuilderContext ctx)
94 return base.MakeExpression (ctx);
96 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
101 public class ParenthesizedExpression : ShimExpression
103 public ParenthesizedExpression (Expression expr, Location loc)
109 protected override Expression DoResolve (ResolveContext ec)
111 var res = expr.Resolve (ec);
112 var constant = res as Constant;
113 if (constant != null && constant.IsLiteral)
114 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
119 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
121 return expr.DoResolveLValue (ec, right_side);
124 public override object Accept (StructuralVisitor visitor)
126 return visitor.Visit (this);
131 // Unary implements unary expressions.
133 public class Unary : Expression
135 public enum Operator : byte {
136 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
140 public readonly Operator Oper;
141 public Expression Expr;
142 ConvCast.Mode enum_conversion;
144 public Unary (Operator op, Expression expr, Location loc)
152 // This routine will attempt to simplify the unary expression when the
153 // argument is a constant.
155 Constant TryReduceConstant (ResolveContext ec, Constant constant)
159 while (e is EmptyConstantCast)
160 e = ((EmptyConstantCast) e).child;
162 if (e is SideEffectConstant) {
163 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
164 return r == null ? null : new SideEffectConstant (r, e, r.Location);
167 TypeSpec expr_type = e.Type;
170 case Operator.UnaryPlus:
171 // Unary numeric promotions
172 switch (expr_type.BuiltinType) {
173 case BuiltinTypeSpec.Type.Byte:
174 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
175 case BuiltinTypeSpec.Type.SByte:
176 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
177 case BuiltinTypeSpec.Type.Short:
178 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
179 case BuiltinTypeSpec.Type.UShort:
180 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
181 case BuiltinTypeSpec.Type.Char:
182 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
184 // Predefined operators
185 case BuiltinTypeSpec.Type.Int:
186 case BuiltinTypeSpec.Type.UInt:
187 case BuiltinTypeSpec.Type.Long:
188 case BuiltinTypeSpec.Type.ULong:
189 case BuiltinTypeSpec.Type.Float:
190 case BuiltinTypeSpec.Type.Double:
191 case BuiltinTypeSpec.Type.Decimal:
197 case Operator.UnaryNegation:
198 // Unary numeric promotions
199 switch (expr_type.BuiltinType) {
200 case BuiltinTypeSpec.Type.Byte:
201 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
202 case BuiltinTypeSpec.Type.SByte:
203 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
204 case BuiltinTypeSpec.Type.Short:
205 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
206 case BuiltinTypeSpec.Type.UShort:
207 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
208 case BuiltinTypeSpec.Type.Char:
209 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
211 // Predefined operators
212 case BuiltinTypeSpec.Type.Int:
213 int ivalue = ((IntConstant) e).Value;
214 if (ivalue == int.MinValue) {
215 if (ec.ConstantCheckState) {
216 ConstantFold.Error_CompileTimeOverflow (ec, loc);
221 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
223 case BuiltinTypeSpec.Type.Long:
224 long lvalue = ((LongConstant) e).Value;
225 if (lvalue == long.MinValue) {
226 if (ec.ConstantCheckState) {
227 ConstantFold.Error_CompileTimeOverflow (ec, loc);
232 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
234 case BuiltinTypeSpec.Type.UInt:
235 UIntLiteral uil = constant as UIntLiteral;
237 if (uil.Value == int.MaxValue + (uint) 1)
238 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
239 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
241 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
244 case BuiltinTypeSpec.Type.ULong:
245 ULongLiteral ull = constant as ULongLiteral;
246 if (ull != null && ull.Value == 9223372036854775808)
247 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
250 case BuiltinTypeSpec.Type.Float:
251 FloatLiteral fl = constant as FloatLiteral;
252 // For better error reporting
254 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
256 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.Double:
259 DoubleLiteral dl = constant as DoubleLiteral;
260 // For better error reporting
262 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
264 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
266 case BuiltinTypeSpec.Type.Decimal:
267 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
272 case Operator.LogicalNot:
273 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
276 bool b = (bool)e.GetValue ();
277 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
279 case Operator.OnesComplement:
280 // Unary numeric promotions
281 switch (expr_type.BuiltinType) {
282 case BuiltinTypeSpec.Type.Byte:
283 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
284 case BuiltinTypeSpec.Type.SByte:
285 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
286 case BuiltinTypeSpec.Type.Short:
287 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
288 case BuiltinTypeSpec.Type.UShort:
289 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
290 case BuiltinTypeSpec.Type.Char:
291 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
293 // Predefined operators
294 case BuiltinTypeSpec.Type.Int:
295 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
296 case BuiltinTypeSpec.Type.UInt:
297 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.Long:
299 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.ULong:
301 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
303 if (e is EnumConstant) {
304 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
307 // Numeric promotion upgraded types to int but for enum constant
308 // original underlying constant type is needed
310 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
311 int v = ((IntConstant) res).Value;
312 switch (((EnumConstant) e).Child.Type.BuiltinType) {
313 case BuiltinTypeSpec.Type.UShort:
314 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
316 case BuiltinTypeSpec.Type.Short:
317 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
319 case BuiltinTypeSpec.Type.Byte:
320 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
322 case BuiltinTypeSpec.Type.SByte:
323 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
328 res = new EnumConstant (res, expr_type);
334 throw new Exception ("Can not constant fold: " + Oper.ToString());
337 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
339 eclass = ExprClass.Value;
341 TypeSpec expr_type = expr.Type;
342 Expression best_expr;
344 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
347 // Primitive types first
349 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
350 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
351 if (best_expr == null)
354 type = best_expr.Type;
360 // E operator ~(E x);
362 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
363 return ResolveEnumOperator (ec, expr, predefined);
365 return ResolveUserType (ec, expr, predefined);
368 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
370 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
371 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
372 if (best_expr == null)
376 enum_conversion = Binary.GetEnumResultCast (underlying_type);
378 return EmptyCast.Create (this, type);
381 public override bool ContainsEmitWithAwait ()
383 return Expr.ContainsEmitWithAwait ();
386 public override Expression CreateExpressionTree (ResolveContext ec)
388 return CreateExpressionTree (ec, null);
391 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
395 case Operator.AddressOf:
396 Error_PointerInsideExpressionTree (ec);
398 case Operator.UnaryNegation:
399 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
400 method_name = "NegateChecked";
402 method_name = "Negate";
404 case Operator.OnesComplement:
405 case Operator.LogicalNot:
408 case Operator.UnaryPlus:
409 method_name = "UnaryPlus";
412 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
415 Arguments args = new Arguments (2);
416 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
418 args.Add (new Argument (user_op));
420 return CreateExpressionFactoryCall (ec, method_name, args);
423 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
425 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
428 // 7.6.1 Unary plus operator
430 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
431 types.Int, types.UInt,
432 types.Long, types.ULong,
433 types.Float, types.Double,
438 // 7.6.2 Unary minus operator
440 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
441 types.Int, types.Long,
442 types.Float, types.Double,
447 // 7.6.3 Logical negation operator
449 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
454 // 7.6.4 Bitwise complement operator
456 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
457 types.Int, types.UInt,
458 types.Long, types.ULong
461 return predefined_operators;
465 // Unary numeric promotions
467 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
469 TypeSpec expr_type = expr.Type;
470 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
471 switch (expr_type.BuiltinType) {
472 case BuiltinTypeSpec.Type.Byte:
473 case BuiltinTypeSpec.Type.SByte:
474 case BuiltinTypeSpec.Type.Short:
475 case BuiltinTypeSpec.Type.UShort:
476 case BuiltinTypeSpec.Type.Char:
477 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
481 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
482 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
487 protected override Expression DoResolve (ResolveContext ec)
489 if (Oper == Operator.AddressOf) {
490 return ResolveAddressOf (ec);
493 Expr = Expr.Resolve (ec);
497 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
498 Arguments args = new Arguments (1);
499 args.Add (new Argument (Expr));
500 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
503 if (Expr.Type.IsNullableType)
504 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
507 // Attempt to use a constant folding operation.
509 Constant cexpr = Expr as Constant;
511 cexpr = TryReduceConstant (ec, cexpr);
516 Expression expr = ResolveOperator (ec, Expr);
518 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
521 // Reduce unary operator on predefined types
523 if (expr == this && Oper == Operator.UnaryPlus)
529 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
534 public override void Emit (EmitContext ec)
536 EmitOperator (ec, type);
539 protected void EmitOperator (EmitContext ec, TypeSpec type)
542 case Operator.UnaryPlus:
546 case Operator.UnaryNegation:
547 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
548 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
549 Expr = Expr.EmitToField (ec);
552 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
553 ec.Emit (OpCodes.Conv_U8);
555 ec.Emit (OpCodes.Sub_Ovf);
558 ec.Emit (OpCodes.Neg);
563 case Operator.LogicalNot:
566 ec.Emit (OpCodes.Ceq);
569 case Operator.OnesComplement:
571 ec.Emit (OpCodes.Not);
574 case Operator.AddressOf:
575 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
579 throw new Exception ("This should not happen: Operator = "
584 // Same trick as in Binary expression
586 if (enum_conversion != 0) {
587 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
588 ConvCast.Emit (ec, enum_conversion);
593 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
595 if (Oper == Operator.LogicalNot)
596 Expr.EmitBranchable (ec, target, !on_true);
598 base.EmitBranchable (ec, target, on_true);
601 public override void EmitSideEffect (EmitContext ec)
603 Expr.EmitSideEffect (ec);
606 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
608 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
609 oper, type.GetSignatureForError ());
612 public override void FlowAnalysis (FlowAnalysisContext fc)
614 FlowAnalysis (fc, false);
617 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
619 FlowAnalysis (fc, true);
622 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
624 if (Oper == Operator.AddressOf) {
625 var vr = Expr as VariableReference;
626 if (vr != null && vr.VariableInfo != null)
627 fc.SetVariableAssigned (vr.VariableInfo);
632 if (Oper == Operator.LogicalNot && conditional) {
633 Expr.FlowAnalysisConditional (fc);
635 var temp = fc.DefiniteAssignmentOnTrue;
636 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
637 fc.DefiniteAssignmentOnFalse = temp;
639 Expr.FlowAnalysis (fc);
644 // Converts operator to System.Linq.Expressions.ExpressionType enum name
646 string GetOperatorExpressionTypeName ()
649 case Operator.OnesComplement:
650 return "OnesComplement";
651 case Operator.LogicalNot:
653 case Operator.UnaryNegation:
655 case Operator.UnaryPlus:
658 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
662 static bool IsFloat (TypeSpec t)
664 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
668 // Returns a stringified representation of the Operator
670 public static string OperName (Operator oper)
673 case Operator.UnaryPlus:
675 case Operator.UnaryNegation:
677 case Operator.LogicalNot:
679 case Operator.OnesComplement:
681 case Operator.AddressOf:
685 throw new NotImplementedException (oper.ToString ());
688 public override SLE.Expression MakeExpression (BuilderContext ctx)
690 var expr = Expr.MakeExpression (ctx);
691 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
694 case Operator.UnaryNegation:
695 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
696 case Operator.LogicalNot:
697 return SLE.Expression.Not (expr);
698 #if NET_4_0 || MOBILE_DYNAMIC
699 case Operator.OnesComplement:
700 return SLE.Expression.OnesComplement (expr);
703 throw new NotImplementedException (Oper.ToString ());
707 Expression ResolveAddressOf (ResolveContext ec)
710 UnsafeError (ec, loc);
712 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
713 if (Expr == null || Expr.eclass != ExprClass.Variable) {
714 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
718 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
722 IVariableReference vr = Expr as IVariableReference;
725 is_fixed = vr.IsFixed;
726 vr.SetHasAddressTaken ();
729 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
732 IFixedExpression fe = Expr as IFixedExpression;
733 is_fixed = fe != null && fe.IsFixed;
736 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
737 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
740 type = PointerContainer.MakeType (ec.Module, Expr.Type);
741 eclass = ExprClass.Value;
745 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
747 expr = DoNumericPromotion (rc, Oper, expr);
748 TypeSpec expr_type = expr.Type;
749 foreach (TypeSpec t in predefined) {
757 // Perform user-operator overload resolution
759 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
761 CSharp.Operator.OpType op_type;
763 case Operator.LogicalNot:
764 op_type = CSharp.Operator.OpType.LogicalNot; break;
765 case Operator.OnesComplement:
766 op_type = CSharp.Operator.OpType.OnesComplement; break;
767 case Operator.UnaryNegation:
768 op_type = CSharp.Operator.OpType.UnaryNegation; break;
769 case Operator.UnaryPlus:
770 op_type = CSharp.Operator.OpType.UnaryPlus; break;
772 throw new InternalErrorException (Oper.ToString ());
775 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
779 Arguments args = new Arguments (1);
780 args.Add (new Argument (expr));
782 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
783 var oper = res.ResolveOperator (ec, ref args);
788 Expr = args [0].Expr;
789 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
793 // Unary user type overload resolution
795 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
797 Expression best_expr = ResolveUserOperator (ec, expr);
798 if (best_expr != null)
801 foreach (TypeSpec t in predefined) {
802 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
803 if (oper_expr == null)
806 if (oper_expr == ErrorExpression.Instance)
810 // decimal type is predefined but has user-operators
812 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
813 oper_expr = ResolveUserType (ec, oper_expr, predefined);
815 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
817 if (oper_expr == null)
820 if (best_expr == null) {
821 best_expr = oper_expr;
825 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
827 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
828 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
830 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
837 best_expr = oper_expr;
840 if (best_expr == null)
844 // HACK: Decimal user-operator is included in standard operators
846 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
850 type = best_expr.Type;
854 protected override void CloneTo (CloneContext clonectx, Expression t)
856 Unary target = (Unary) t;
858 target.Expr = Expr.Clone (clonectx);
861 public override object Accept (StructuralVisitor visitor)
863 return visitor.Visit (this);
869 // Unary operators are turned into Indirection expressions
870 // after semantic analysis (this is so we can take the address
871 // of an indirection).
873 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
875 LocalTemporary temporary;
878 public Indirection (Expression expr, Location l)
884 public Expression Expr {
890 public bool IsFixed {
894 public override Location StartLocation {
896 return expr.StartLocation;
900 protected override void CloneTo (CloneContext clonectx, Expression t)
902 Indirection target = (Indirection) t;
903 target.expr = expr.Clone (clonectx);
906 public override bool ContainsEmitWithAwait ()
908 throw new NotImplementedException ();
911 public override Expression CreateExpressionTree (ResolveContext ec)
913 Error_PointerInsideExpressionTree (ec);
917 public override void Emit (EmitContext ec)
922 ec.EmitLoadFromPtr (Type);
925 public void Emit (EmitContext ec, bool leave_copy)
929 ec.Emit (OpCodes.Dup);
930 temporary = new LocalTemporary (expr.Type);
931 temporary.Store (ec);
935 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
937 prepared = isCompound;
942 ec.Emit (OpCodes.Dup);
946 ec.Emit (OpCodes.Dup);
947 temporary = new LocalTemporary (source.Type);
948 temporary.Store (ec);
951 ec.EmitStoreFromPtr (type);
953 if (temporary != null) {
955 temporary.Release (ec);
959 public void AddressOf (EmitContext ec, AddressOp Mode)
964 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
966 return DoResolve (ec);
969 protected override Expression DoResolve (ResolveContext ec)
971 expr = expr.Resolve (ec);
976 UnsafeError (ec, loc);
978 var pc = expr.Type as PointerContainer;
981 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
987 if (type.Kind == MemberKind.Void) {
988 Error_VoidPointerOperation (ec);
992 eclass = ExprClass.Variable;
996 public override object Accept (StructuralVisitor visitor)
998 return visitor.Visit (this);
1003 /// Unary Mutator expressions (pre and post ++ and --)
1007 /// UnaryMutator implements ++ and -- expressions. It derives from
1008 /// ExpressionStatement becuase the pre/post increment/decrement
1009 /// operators can be used in a statement context.
1011 /// FIXME: Idea, we could split this up in two classes, one simpler
1012 /// for the common case, and one with the extra fields for more complex
1013 /// classes (indexers require temporary access; overloaded require method)
1016 public class UnaryMutator : ExpressionStatement
1018 class DynamicPostMutator : Expression, IAssignMethod
1020 LocalTemporary temp;
1023 public DynamicPostMutator (Expression expr)
1026 this.type = expr.Type;
1027 this.loc = expr.Location;
1030 public override Expression CreateExpressionTree (ResolveContext ec)
1032 throw new NotImplementedException ("ET");
1035 protected override Expression DoResolve (ResolveContext rc)
1037 eclass = expr.eclass;
1041 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1043 expr.DoResolveLValue (ec, right_side);
1044 return DoResolve (ec);
1047 public override void Emit (EmitContext ec)
1052 public void Emit (EmitContext ec, bool leave_copy)
1054 throw new NotImplementedException ();
1058 // Emits target assignment using unmodified source value
1060 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1063 // Allocate temporary variable to keep original value before it's modified
1065 temp = new LocalTemporary (type);
1069 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1080 public enum Mode : byte {
1087 PreDecrement = IsDecrement,
1088 PostIncrement = IsPost,
1089 PostDecrement = IsPost | IsDecrement
1093 bool is_expr, recurse;
1095 protected Expression expr;
1097 // Holds the real operation
1098 Expression operation;
1100 public UnaryMutator (Mode m, Expression e, Location loc)
1107 public Mode UnaryMutatorMode {
1113 public Expression Expr {
1119 public override Location StartLocation {
1121 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1125 public override bool ContainsEmitWithAwait ()
1127 return expr.ContainsEmitWithAwait ();
1130 public override Expression CreateExpressionTree (ResolveContext ec)
1132 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1135 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1138 // Predefined ++ and -- operators exist for the following types:
1139 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1141 return new TypeSpec[] {
1157 protected override Expression DoResolve (ResolveContext ec)
1159 expr = expr.Resolve (ec);
1161 if (expr == null || expr.Type == InternalType.ErrorType)
1164 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1166 // Handle postfix unary operators using local
1167 // temporary variable
1169 if ((mode & Mode.IsPost) != 0)
1170 expr = new DynamicPostMutator (expr);
1172 Arguments args = new Arguments (1);
1173 args.Add (new Argument (expr));
1174 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1177 if (expr.Type.IsNullableType)
1178 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1180 return DoResolveOperation (ec);
1183 protected Expression DoResolveOperation (ResolveContext ec)
1185 eclass = ExprClass.Value;
1188 if (expr is RuntimeValueExpression) {
1191 // Use itself at the top of the stack
1192 operation = new EmptyExpression (type);
1196 // The operand of the prefix/postfix increment decrement operators
1197 // should be an expression that is classified as a variable,
1198 // a property access or an indexer access
1200 // TODO: Move to parser, expr is ATypeNameExpression
1201 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1202 expr = expr.ResolveLValue (ec, expr);
1204 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1208 // Step 1: Try to find a user operator, it has priority over predefined ones
1210 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1211 var methods = MemberCache.GetUserOperator (type, user_op, false);
1213 if (methods != null) {
1214 Arguments args = new Arguments (1);
1215 args.Add (new Argument (expr));
1217 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1218 var method = res.ResolveOperator (ec, ref args);
1222 args[0].Expr = operation;
1223 operation = new UserOperatorCall (method, args, null, loc);
1224 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1229 // Step 2: Try predefined types
1232 Expression source = null;
1233 bool primitive_type;
1236 // Predefined without user conversion first for speed-up
1238 // Predefined ++ and -- operators exist for the following types:
1239 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1241 switch (type.BuiltinType) {
1242 case BuiltinTypeSpec.Type.Byte:
1243 case BuiltinTypeSpec.Type.SByte:
1244 case BuiltinTypeSpec.Type.Short:
1245 case BuiltinTypeSpec.Type.UShort:
1246 case BuiltinTypeSpec.Type.Int:
1247 case BuiltinTypeSpec.Type.UInt:
1248 case BuiltinTypeSpec.Type.Long:
1249 case BuiltinTypeSpec.Type.ULong:
1250 case BuiltinTypeSpec.Type.Char:
1251 case BuiltinTypeSpec.Type.Float:
1252 case BuiltinTypeSpec.Type.Double:
1253 case BuiltinTypeSpec.Type.Decimal:
1255 primitive_type = true;
1258 primitive_type = false;
1260 // ++/-- on pointer variables of all types except void*
1261 if (type.IsPointer) {
1262 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1263 Error_VoidPointerOperation (ec);
1269 Expression best_source = null;
1270 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1271 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1273 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1277 if (best_source == null) {
1278 best_source = source;
1282 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1287 best_source = source;
1291 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1295 source = best_source;
1298 // ++/-- on enum types
1299 if (source == null && type.IsEnum)
1302 if (source == null) {
1303 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1310 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1311 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1312 operation = new Binary (op, source, one);
1313 operation = operation.Resolve (ec);
1314 if (operation == null)
1315 throw new NotImplementedException ("should not be reached");
1317 if (operation.Type != type) {
1319 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1321 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1327 void EmitCode (EmitContext ec, bool is_expr)
1330 this.is_expr = is_expr;
1331 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1334 public override void Emit (EmitContext ec)
1337 // We use recurse to allow ourselfs to be the source
1338 // of an assignment. This little hack prevents us from
1339 // having to allocate another expression
1342 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1350 EmitCode (ec, true);
1353 protected virtual void EmitOperation (EmitContext ec)
1355 operation.Emit (ec);
1358 public override void EmitStatement (EmitContext ec)
1360 EmitCode (ec, false);
1363 public override void FlowAnalysis (FlowAnalysisContext fc)
1365 expr.FlowAnalysis (fc);
1369 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1371 string GetOperatorExpressionTypeName ()
1373 return IsDecrement ? "Decrement" : "Increment";
1377 get { return (mode & Mode.IsDecrement) != 0; }
1381 #if NET_4_0 || MOBILE_DYNAMIC
1382 public override SLE.Expression MakeExpression (BuilderContext ctx)
1384 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1385 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1386 return SLE.Expression.Assign (target, source);
1390 public static string OperName (Mode oper)
1392 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1395 protected override void CloneTo (CloneContext clonectx, Expression t)
1397 UnaryMutator target = (UnaryMutator) t;
1399 target.expr = expr.Clone (clonectx);
1402 public override object Accept (StructuralVisitor visitor)
1404 return visitor.Visit (this);
1410 // Base class for the `is' and `as' operators
1412 public abstract class Probe : Expression
1414 public Expression ProbeType;
1415 protected Expression expr;
1416 protected TypeSpec probe_type_expr;
1418 protected Probe (Expression expr, Expression probe_type, Location l)
1420 ProbeType = probe_type;
1425 public Expression Expr {
1431 public override bool ContainsEmitWithAwait ()
1433 return expr.ContainsEmitWithAwait ();
1436 protected Expression ResolveCommon (ResolveContext rc)
1438 expr = expr.Resolve (rc);
1442 ResolveProbeType (rc);
1443 if (probe_type_expr == null)
1446 if (probe_type_expr.IsStatic) {
1447 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1448 probe_type_expr.GetSignatureForError ());
1452 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1453 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1458 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1459 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1467 protected virtual void ResolveProbeType (ResolveContext rc)
1469 probe_type_expr = ProbeType.ResolveAsType (rc);
1472 public override void EmitSideEffect (EmitContext ec)
1474 expr.EmitSideEffect (ec);
1477 public override void FlowAnalysis (FlowAnalysisContext fc)
1479 expr.FlowAnalysis (fc);
1482 protected abstract string OperatorName { get; }
1484 protected override void CloneTo (CloneContext clonectx, Expression t)
1486 Probe target = (Probe) t;
1488 target.expr = expr.Clone (clonectx);
1489 target.ProbeType = ProbeType.Clone (clonectx);
1495 /// Implementation of the `is' operator.
1497 public class Is : Probe
1499 Nullable.Unwrap expr_unwrap;
1500 MethodSpec number_mg;
1501 Arguments number_args;
1503 public Is (Expression expr, Expression probe_type, Location l)
1504 : base (expr, probe_type, l)
1508 protected override string OperatorName {
1509 get { return "is"; }
1512 public LocalVariable Variable { get; set; }
1514 public override Expression CreateExpressionTree (ResolveContext ec)
1516 if (Variable != null)
1517 throw new NotSupportedException ();
1519 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1520 expr.CreateExpressionTree (ec),
1521 new TypeOf (probe_type_expr, loc));
1523 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1526 Expression CreateConstantResult (ResolveContext rc, bool result)
1529 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1530 probe_type_expr.GetSignatureForError ());
1532 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1533 probe_type_expr.GetSignatureForError ());
1535 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1536 return expr.IsSideEffectFree ?
1537 ReducedExpression.Create (c, this) :
1538 new SideEffectConstant (c, this, loc);
1541 public override void Emit (EmitContext ec)
1543 if (probe_type_expr == null) {
1544 if (ProbeType is WildcardPattern) {
1545 expr.EmitSideEffect (ec);
1546 ProbeType.Emit (ec);
1548 EmitPatternMatch (ec);
1555 if (expr_unwrap == null) {
1557 ec.Emit (OpCodes.Cgt_Un);
1561 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1563 if (probe_type_expr == null) {
1564 EmitPatternMatch (ec);
1569 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1572 void EmitPatternMatch (EmitContext ec)
1574 var no_match = ec.DefineLabel ();
1575 var end = ec.DefineLabel ();
1577 if (expr_unwrap != null) {
1578 expr_unwrap.EmitCheck (ec);
1580 if (ProbeType.IsNull) {
1582 ec.Emit (OpCodes.Ceq);
1586 ec.Emit (OpCodes.Brfalse_S, no_match);
1587 expr_unwrap.Emit (ec);
1588 ProbeType.Emit (ec);
1589 ec.Emit (OpCodes.Ceq);
1590 ec.Emit (OpCodes.Br_S, end);
1591 ec.MarkLabel (no_match);
1597 if (number_args != null && number_args.Count == 3) {
1598 var ce = new CallEmitter ();
1599 ce.Emit (ec, number_mg, number_args, loc);
1603 var probe_type = ProbeType.Type;
1606 ec.Emit (OpCodes.Isinst, probe_type);
1607 ec.Emit (OpCodes.Dup);
1608 ec.Emit (OpCodes.Brfalse, no_match);
1610 bool complex_pattern = ProbeType is ComplexPatternExpression;
1611 Label prev = ec.RecursivePatternLabel;
1612 if (complex_pattern)
1613 ec.RecursivePatternLabel = ec.DefineLabel ();
1615 if (number_mg != null) {
1616 var ce = new CallEmitter ();
1617 ce.Emit (ec, number_mg, number_args, loc);
1619 if (TypeSpec.IsValueType (probe_type))
1620 ec.Emit (OpCodes.Unbox_Any, probe_type);
1622 ProbeType.Emit (ec);
1623 if (complex_pattern) {
1626 ec.Emit (OpCodes.Ceq);
1629 ec.Emit (OpCodes.Br_S, end);
1630 ec.MarkLabel (no_match);
1632 ec.Emit (OpCodes.Pop);
1634 if (complex_pattern)
1635 ec.MarkLabel (ec.RecursivePatternLabel);
1637 ec.RecursivePatternLabel = prev;
1643 void EmitLoad (EmitContext ec)
1645 Label no_value_label = new Label ();
1647 if (expr_unwrap != null) {
1648 expr_unwrap.EmitCheck (ec);
1650 if (Variable == null)
1653 ec.Emit (OpCodes.Dup);
1654 no_value_label = ec.DefineLabel ();
1655 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1656 expr_unwrap.Emit (ec);
1660 // Only to make verifier happy
1661 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1662 ec.Emit (OpCodes.Box, expr.Type);
1664 ec.Emit (OpCodes.Isinst, probe_type_expr);
1667 if (Variable != null) {
1668 bool value_on_stack;
1669 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1670 ec.Emit (OpCodes.Dup);
1671 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1672 value_on_stack = true;
1674 value_on_stack = false;
1677 Variable.CreateBuilder (ec);
1678 Variable.EmitAssign (ec);
1680 if (expr_unwrap != null) {
1681 ec.MarkLabel (no_value_label);
1682 } else if (!value_on_stack) {
1688 protected override Expression DoResolve (ResolveContext rc)
1690 if (ResolveCommon (rc) == null)
1693 type = rc.BuiltinTypes.Bool;
1694 eclass = ExprClass.Value;
1696 if (probe_type_expr == null)
1697 return ResolveMatchingExpression (rc);
1699 var res = ResolveResultExpression (rc);
1700 if (Variable != null) {
1701 if (res is Constant)
1702 throw new NotImplementedException ("constant in type pattern matching");
1704 Variable.Type = probe_type_expr;
1705 var bc = rc as BlockContext;
1707 Variable.PrepareAssignmentAnalysis (bc);
1713 public override void FlowAnalysis (FlowAnalysisContext fc)
1715 base.FlowAnalysis (fc);
1717 if (Variable != null)
1718 fc.SetVariableAssigned (Variable.VariableInfo, true);
1721 protected override void ResolveProbeType (ResolveContext rc)
1723 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1724 if (ProbeType is PatternExpression) {
1725 ProbeType.Resolve (rc);
1730 // Have to use session recording because we don't have reliable type probing
1731 // mechanism (similar issue as in attributes resolving)
1733 // TODO: This is still wrong because ResolveAsType can be destructive
1735 var type_printer = new SessionReportPrinter ();
1736 var prev_recorder = rc.Report.SetPrinter (type_printer);
1738 probe_type_expr = ProbeType.ResolveAsType (rc);
1739 type_printer.EndSession ();
1741 if (probe_type_expr != null) {
1742 type_printer.Merge (rc.Report.Printer);
1743 rc.Report.SetPrinter (prev_recorder);
1747 var vexpr = ProbeType as VarExpr;
1748 if (vexpr != null && vexpr.InferType (rc, expr)) {
1749 probe_type_expr = vexpr.Type;
1750 rc.Report.SetPrinter (prev_recorder);
1754 var expr_printer = new SessionReportPrinter ();
1755 rc.Report.SetPrinter (expr_printer);
1756 ProbeType = ProbeType.Resolve (rc);
1757 expr_printer.EndSession ();
1759 if (ProbeType != null) {
1760 expr_printer.Merge (rc.Report.Printer);
1762 type_printer.Merge (rc.Report.Printer);
1765 rc.Report.SetPrinter (prev_recorder);
1769 base.ResolveProbeType (rc);
1772 Expression ResolveMatchingExpression (ResolveContext rc)
1774 var mc = ProbeType as Constant;
1776 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1777 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1782 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1784 var c = Expr as Constant;
1786 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1791 if (Expr.Type.IsNullableType) {
1792 expr_unwrap = new Nullable.Unwrap (Expr);
1793 expr_unwrap.Resolve (rc);
1794 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1795 } else if (ProbeType.Type == Expr.Type) {
1796 // TODO: Better error handling
1797 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1798 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1799 var helper = rc.Module.CreatePatterMatchingHelper ();
1800 number_mg = helper.NumberMatcher.Spec;
1803 // There are actually 3 arguments but the first one is already on the stack
1805 number_args = new Arguments (3);
1806 if (!ProbeType.Type.IsEnum)
1807 number_args.Add (new Argument (Expr));
1809 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1810 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1816 if (ProbeType is PatternExpression) {
1817 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1818 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1824 // TODO: Better error message
1825 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1829 Expression ResolveResultExpression (ResolveContext ec)
1831 TypeSpec d = expr.Type;
1832 bool d_is_nullable = false;
1835 // If E is a method group or the null literal, or if the type of E is a reference
1836 // type or a nullable type and the value of E is null, the result is false
1838 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1839 return CreateConstantResult (ec, false);
1841 if (d.IsNullableType) {
1842 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1843 if (!ut.IsGenericParameter) {
1845 d_is_nullable = true;
1849 TypeSpec t = probe_type_expr;
1850 bool t_is_nullable = false;
1851 if (t.IsNullableType) {
1852 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1853 if (!ut.IsGenericParameter) {
1855 t_is_nullable = true;
1862 // D and T are the same value types but D can be null
1864 if (d_is_nullable && !t_is_nullable) {
1865 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1870 // The result is true if D and T are the same value types
1872 return CreateConstantResult (ec, true);
1875 var tp = d as TypeParameterSpec;
1877 return ResolveGenericParameter (ec, t, tp);
1880 // An unboxing conversion exists
1882 if (Convert.ExplicitReferenceConversionExists (d, t))
1886 // open generic type
1888 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1891 var tps = t as TypeParameterSpec;
1893 return ResolveGenericParameter (ec, d, tps);
1895 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1896 ec.Report.Warning (1981, 3, loc,
1897 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1898 OperatorName, t.GetSignatureForError ());
1901 if (TypeManager.IsGenericParameter (d))
1902 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1904 if (TypeSpec.IsValueType (d)) {
1905 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1906 if (d_is_nullable && !t_is_nullable) {
1907 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1911 return CreateConstantResult (ec, true);
1914 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1915 var c = expr as Constant;
1917 return CreateConstantResult (ec, !c.IsNull);
1920 // Do not optimize for imported type or dynamic type
1922 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1923 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1927 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1931 // Turn is check into simple null check for implicitly convertible reference types
1933 return ReducedExpression.Create (
1934 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1938 if (Convert.ExplicitReferenceConversionExists (d, t))
1942 // open generic type
1944 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1949 return CreateConstantResult (ec, false);
1952 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1954 if (t.IsReferenceType) {
1956 return CreateConstantResult (ec, false);
1959 if (expr.Type.IsGenericParameter) {
1960 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1961 return CreateConstantResult (ec, true);
1963 expr = new BoxedCast (expr, d);
1969 public override object Accept (StructuralVisitor visitor)
1971 return visitor.Visit (this);
1975 class WildcardPattern : PatternExpression
1977 public WildcardPattern (Location loc)
1982 protected override Expression DoResolve (ResolveContext rc)
1984 eclass = ExprClass.Value;
1985 type = rc.BuiltinTypes.Object;
1989 public override void Emit (EmitContext ec)
1995 class RecursivePattern : ComplexPatternExpression
1997 MethodGroupExpr operator_mg;
1998 Arguments operator_args;
2000 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2001 : base (typeExpresion, loc)
2003 Arguments = arguments;
2006 public Arguments Arguments { get; private set; }
2008 protected override Expression DoResolve (ResolveContext rc)
2010 type = TypeExpression.ResolveAsType (rc);
2014 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2015 if (operators == null) {
2016 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2020 var ops = FindMatchingOverloads (operators);
2022 // TODO: better error message
2023 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2028 Arguments.Resolve (rc, out dynamic_args);
2030 throw new NotImplementedException ("dynamic argument");
2032 var op = FindBestOverload (rc, ops);
2034 // TODO: better error message
2035 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2039 var op_types = op.Parameters.Types;
2040 operator_args = new Arguments (op_types.Length);
2041 operator_args.Add (new Argument (new EmptyExpression (type)));
2043 for (int i = 0; i < Arguments.Count; ++i) {
2044 // TODO: Needs releasing optimization
2045 var lt = new LocalTemporary (op_types [i + 1]);
2046 operator_args.Add (new Argument (lt, Argument.AType.Out));
2048 if (comparisons == null)
2049 comparisons = new Expression[Arguments.Count];
2054 var arg = Arguments [i];
2055 var named = arg as NamedArgument;
2056 if (named != null) {
2057 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2058 expr = Arguments [arg_comp_index].Expr;
2064 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2067 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2069 eclass = ExprClass.Value;
2073 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2075 int arg_count = Arguments.Count + 1;
2076 List<MethodSpec> best = null;
2077 foreach (MethodSpec method in members) {
2078 var pm = method.Parameters;
2079 if (pm.Count != arg_count)
2082 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2084 for (int ii = 1; ii < pm.Count; ++ii) {
2085 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2095 best = new List<MethodSpec> ();
2103 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2105 for (int ii = 0; ii < Arguments.Count; ++ii) {
2106 var arg = Arguments [ii];
2107 var expr = arg.Expr;
2108 if (expr is WildcardPattern)
2111 var na = arg as NamedArgument;
2112 for (int i = 0; i < methods.Count; ++i) {
2113 var pd = methods [i].Parameters;
2117 index = pd.GetParameterIndexByName (na.Name);
2119 methods.RemoveAt (i--);
2126 var m = pd.Types [index];
2127 if (!Convert.ImplicitConversionExists (rc, expr, m))
2128 methods.RemoveAt (i--);
2132 if (methods.Count != 1)
2138 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2140 operator_mg.EmitCall (ec, operator_args, false);
2141 ec.Emit (OpCodes.Brfalse, target);
2143 base.EmitBranchable (ec, target, on_true);
2146 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2148 if (expr is WildcardPattern)
2149 return new EmptyExpression (expr.Type);
2151 var recursive = expr as RecursivePattern;
2152 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2156 if (recursive != null) {
2157 recursive.SetParentInstance (lt);
2161 // TODO: Better error handling
2162 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2165 public void SetParentInstance (Expression instance)
2167 operator_args [0] = new Argument (instance);
2171 class PropertyPattern : ComplexPatternExpression
2173 LocalTemporary instance;
2175 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2176 : base (typeExpresion, loc)
2181 public List<PropertyPatternMember> Members { get; private set; }
2183 protected override Expression DoResolve (ResolveContext rc)
2185 type = TypeExpression.ResolveAsType (rc);
2189 comparisons = new Expression[Members.Count];
2191 // TODO: optimize when source is VariableReference, it'd save dup+pop
2192 instance = new LocalTemporary (type);
2194 for (int i = 0; i < Members.Count; i++) {
2195 var lookup = Members [i];
2197 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2198 if (member == null) {
2199 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2200 if (member != null) {
2201 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2206 if (member == null) {
2207 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2211 var pe = member as PropertyExpr;
2212 if (pe == null || member is FieldExpr) {
2213 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2217 // TODO: Obsolete checks
2218 // TODO: check accessibility
2219 if (pe != null && !pe.PropertyInfo.HasGet) {
2220 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2224 var expr = lookup.Expr.Resolve (rc);
2228 var me = (MemberExpr)member;
2229 me.InstanceExpression = instance;
2231 comparisons [i] = ResolveComparison (rc, expr, me);
2234 eclass = ExprClass.Value;
2238 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2240 if (expr is WildcardPattern)
2241 return new EmptyExpression (expr.Type);
2243 return new Is (instance, expr, expr.Location).Resolve (rc);
2246 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2248 instance.Store (ec);
2250 base.EmitBranchable (ec, target, on_true);
2254 class PropertyPatternMember
2256 public PropertyPatternMember (string name, Expression expr, Location loc)
2263 public string Name { get; private set; }
2264 public Expression Expr { get; private set; }
2265 public Location Location { get; private set; }
2268 abstract class PatternExpression : Expression
2270 protected PatternExpression (Location loc)
2275 public override Expression CreateExpressionTree (ResolveContext ec)
2277 throw new NotImplementedException ();
2281 abstract class ComplexPatternExpression : PatternExpression
2283 protected Expression[] comparisons;
2285 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2288 TypeExpression = typeExpresion;
2291 public ATypeNameExpression TypeExpression { get; private set; }
2293 public override void Emit (EmitContext ec)
2295 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2298 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2300 if (comparisons != null) {
2301 foreach (var comp in comparisons) {
2302 comp.EmitBranchable (ec, target, false);
2309 /// Implementation of the `as' operator.
2311 public class As : Probe {
2313 public As (Expression expr, Expression probe_type, Location l)
2314 : base (expr, probe_type, l)
2318 protected override string OperatorName {
2319 get { return "as"; }
2322 public override Expression CreateExpressionTree (ResolveContext ec)
2324 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2325 expr.CreateExpressionTree (ec),
2326 new TypeOf (probe_type_expr, loc));
2328 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2331 public override void Emit (EmitContext ec)
2335 ec.Emit (OpCodes.Isinst, type);
2337 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2338 ec.Emit (OpCodes.Unbox_Any, type);
2341 protected override Expression DoResolve (ResolveContext ec)
2343 if (ResolveCommon (ec) == null)
2346 type = probe_type_expr;
2347 eclass = ExprClass.Value;
2348 TypeSpec etype = expr.Type;
2350 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2351 if (TypeManager.IsGenericParameter (type)) {
2352 ec.Report.Error (413, loc,
2353 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2354 probe_type_expr.GetSignatureForError ());
2356 ec.Report.Error (77, loc,
2357 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2358 type.GetSignatureForError ());
2363 if (expr.IsNull && type.IsNullableType) {
2364 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2367 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2368 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2372 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2374 e = EmptyCast.Create (e, type);
2375 return ReducedExpression.Create (e, this).Resolve (ec);
2378 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2379 if (TypeManager.IsGenericParameter (etype))
2380 expr = new BoxedCast (expr, etype);
2385 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2386 expr = new BoxedCast (expr, etype);
2390 if (etype != InternalType.ErrorType) {
2391 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2392 etype.GetSignatureForError (), type.GetSignatureForError ());
2398 public override object Accept (StructuralVisitor visitor)
2400 return visitor.Visit (this);
2405 // This represents a typecast in the source language.
2407 public class Cast : ShimExpression {
2408 Expression target_type;
2410 public Cast (Expression cast_type, Expression expr, Location loc)
2413 this.target_type = cast_type;
2417 public Expression TargetType {
2418 get { return target_type; }
2421 protected override Expression DoResolve (ResolveContext ec)
2423 expr = expr.Resolve (ec);
2427 type = target_type.ResolveAsType (ec);
2431 if (type.IsStatic) {
2432 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2436 if (type.IsPointer && !ec.IsUnsafe) {
2437 UnsafeError (ec, loc);
2440 eclass = ExprClass.Value;
2442 Constant c = expr as Constant;
2444 c = c.Reduce (ec, type);
2449 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2451 return EmptyCast.Create (res, type);
2456 protected override void CloneTo (CloneContext clonectx, Expression t)
2458 Cast target = (Cast) t;
2460 target.target_type = target_type.Clone (clonectx);
2461 target.expr = expr.Clone (clonectx);
2464 public override object Accept (StructuralVisitor visitor)
2466 return visitor.Visit (this);
2470 public class ImplicitCast : ShimExpression
2474 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2477 this.loc = expr.Location;
2479 this.arrayAccess = arrayAccess;
2482 protected override Expression DoResolve (ResolveContext ec)
2484 expr = expr.Resolve (ec);
2489 expr = ConvertExpressionToArrayIndex (ec, expr);
2491 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2498 // C# 2.0 Default value expression
2500 public class DefaultValueExpression : Expression
2504 public DefaultValueExpression (Expression expr, Location loc)
2510 public Expression Expr {
2516 public override bool IsSideEffectFree {
2522 public override bool ContainsEmitWithAwait ()
2527 public override Expression CreateExpressionTree (ResolveContext ec)
2529 Arguments args = new Arguments (2);
2530 args.Add (new Argument (this));
2531 args.Add (new Argument (new TypeOf (type, loc)));
2532 return CreateExpressionFactoryCall (ec, "Constant", args);
2535 protected override Expression DoResolve (ResolveContext ec)
2537 type = expr.ResolveAsType (ec);
2541 if (type.IsStatic) {
2542 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2546 return new NullLiteral (Location).ConvertImplicitly (type);
2548 if (TypeSpec.IsReferenceType (type))
2549 return new NullConstant (type, loc);
2551 Constant c = New.Constantify (type, expr.Location);
2555 eclass = ExprClass.Variable;
2559 public override void Emit (EmitContext ec)
2561 LocalTemporary temp_storage = new LocalTemporary(type);
2563 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2564 ec.Emit(OpCodes.Initobj, type);
2565 temp_storage.Emit(ec);
2566 temp_storage.Release (ec);
2569 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
2570 public override SLE.Expression MakeExpression (BuilderContext ctx)
2572 return SLE.Expression.Default (type.GetMetaInfo ());
2576 protected override void CloneTo (CloneContext clonectx, Expression t)
2578 DefaultValueExpression target = (DefaultValueExpression) t;
2580 target.expr = expr.Clone (clonectx);
2583 public override object Accept (StructuralVisitor visitor)
2585 return visitor.Visit (this);
2590 /// Binary operators
2592 public class Binary : Expression, IDynamicBinder
2594 public class PredefinedOperator
2596 protected readonly TypeSpec left;
2597 protected readonly TypeSpec right;
2598 protected readonly TypeSpec left_unwrap;
2599 protected readonly TypeSpec right_unwrap;
2600 public readonly Operator OperatorsMask;
2601 public TypeSpec ReturnType;
2603 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2604 : this (ltype, rtype, op_mask, ltype)
2608 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2609 : this (type, type, op_mask, return_type)
2613 public PredefinedOperator (TypeSpec type, Operator op_mask)
2614 : this (type, type, op_mask, type)
2618 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2620 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2621 throw new InternalErrorException ("Only masked values can be used");
2623 if ((op_mask & Operator.NullableMask) != 0) {
2624 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2625 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2627 left_unwrap = ltype;
2628 right_unwrap = rtype;
2633 this.OperatorsMask = op_mask;
2634 this.ReturnType = return_type;
2637 public bool IsLifted {
2639 return (OperatorsMask & Operator.NullableMask) != 0;
2643 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2647 var left_expr = b.left;
2648 var right_expr = b.right;
2650 b.type = ReturnType;
2653 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2654 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2655 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2658 if (right_expr.IsNull) {
2659 if ((b.oper & Operator.EqualityMask) != 0) {
2660 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2661 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2662 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2663 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2664 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2666 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2667 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2669 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2670 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2672 return b.CreateLiftedValueTypeResult (rc, left);
2674 } else if (left_expr.IsNull) {
2675 if ((b.oper & Operator.EqualityMask) != 0) {
2676 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2677 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2678 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2679 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2680 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2682 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2683 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2685 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2686 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2688 return b.CreateLiftedValueTypeResult (rc, right);
2694 // A user operators does not support multiple user conversions, but decimal type
2695 // is considered to be predefined type therefore we apply predefined operators rules
2696 // and then look for decimal user-operator implementation
2698 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2699 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2700 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2702 return b.ResolveUserOperator (rc, b.left, b.right);
2705 c = right_expr as Constant;
2707 if (c.IsDefaultValue) {
2711 // (expr + 0) to expr
2712 // (expr - 0) to expr
2713 // (bool? | false) to bool?
2715 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2716 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2717 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2718 return ReducedExpression.Create (b.left, b).Resolve (rc);
2722 // Optimizes (value &/&& 0) to 0
2724 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2725 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2726 return ReducedExpression.Create (side_effect, b);
2730 // Optimizes (bool? & true) to bool?
2732 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2733 return ReducedExpression.Create (b.left, b).Resolve (rc);
2737 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2738 return ReducedExpression.Create (b.left, b).Resolve (rc);
2740 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2741 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2745 c = b.left as Constant;
2747 if (c.IsDefaultValue) {
2751 // (0 + expr) to expr
2752 // (false | bool?) to bool?
2754 if (b.oper == Operator.Addition ||
2755 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2756 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2757 return ReducedExpression.Create (b.right, b).Resolve (rc);
2761 // Optimizes (false && expr) to false
2763 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2764 // No rhs side-effects
2765 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2766 return ReducedExpression.Create (c, b);
2770 // Optimizes (0 & value) to 0
2772 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2773 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2774 return ReducedExpression.Create (side_effect, b);
2778 // Optimizes (true & bool?) to bool?
2780 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2781 return ReducedExpression.Create (b.right, b).Resolve (rc);
2785 // Optimizes (true || expr) to true
2787 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2788 // No rhs side-effects
2789 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2790 return ReducedExpression.Create (c, b);
2794 if (b.oper == Operator.Multiply && c.IsOneInteger)
2795 return ReducedExpression.Create (b.right, b).Resolve (rc);
2799 var lifted = new Nullable.LiftedBinaryOperator (b);
2801 TypeSpec ltype, rtype;
2802 if (b.left.Type.IsNullableType) {
2803 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2804 ltype = left_unwrap;
2809 if (b.right.Type.IsNullableType) {
2810 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2811 rtype = right_unwrap;
2816 lifted.Left = b.left.IsNull ?
2818 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2820 lifted.Right = b.right.IsNull ?
2822 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2824 return lifted.Resolve (rc);
2827 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2828 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2833 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2836 // We are dealing with primitive types only
2838 return left == ltype && ltype == rtype;
2841 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2844 if (left == lexpr.Type && right == rexpr.Type)
2847 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2848 Convert.ImplicitConversionExists (ec, rexpr, right);
2851 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2853 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2854 return best_operator;
2856 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2860 if (left != null && best_operator.left != null) {
2861 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2865 // When second argument is same as the first one, the result is same
2867 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2868 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2871 if (result == 0 || result > 2)
2874 return result == 1 ? best_operator : this;
2878 sealed class PredefinedStringOperator : PredefinedOperator
2880 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2881 : base (type, type, op_mask, retType)
2885 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2886 : base (ltype, rtype, op_mask, retType)
2890 public override Expression ConvertResult (ResolveContext ec, Binary b)
2893 // Use original expression for nullable arguments
2895 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2897 b.left = unwrap.Original;
2899 unwrap = b.right as Nullable.Unwrap;
2901 b.right = unwrap.Original;
2903 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2904 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2907 // Start a new concat expression using converted expression
2909 return StringConcat.Create (ec, b.left, b.right, b.loc);
2913 sealed class PredefinedEqualityOperator : PredefinedOperator
2915 MethodSpec equal_method, inequal_method;
2917 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2918 : base (arg, arg, Operator.EqualityMask, retType)
2922 public override Expression ConvertResult (ResolveContext ec, Binary b)
2924 b.type = ReturnType;
2926 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2927 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2929 Arguments args = new Arguments (2);
2930 args.Add (new Argument (b.left));
2931 args.Add (new Argument (b.right));
2934 if (b.oper == Operator.Equality) {
2935 if (equal_method == null) {
2936 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2937 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2938 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2939 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2941 throw new NotImplementedException (left.GetSignatureForError ());
2944 method = equal_method;
2946 if (inequal_method == null) {
2947 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2948 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2949 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2950 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2952 throw new NotImplementedException (left.GetSignatureForError ());
2955 method = inequal_method;
2958 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2962 class PredefinedPointerOperator : PredefinedOperator
2964 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2965 : base (ltype, rtype, op_mask)
2969 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2970 : base (ltype, rtype, op_mask, retType)
2974 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2975 : base (type, op_mask, return_type)
2979 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2982 if (!lexpr.Type.IsPointer)
2985 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2989 if (right == null) {
2990 if (!rexpr.Type.IsPointer)
2993 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3000 public override Expression ConvertResult (ResolveContext ec, Binary b)
3003 b.left = EmptyCast.Create (b.left, left);
3004 } else if (right != null) {
3005 b.right = EmptyCast.Create (b.right, right);
3008 TypeSpec r_type = ReturnType;
3009 Expression left_arg, right_arg;
3010 if (r_type == null) {
3013 right_arg = b.right;
3014 r_type = b.left.Type;
3018 r_type = b.right.Type;
3022 right_arg = b.right;
3025 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3030 public enum Operator {
3031 Multiply = 0 | ArithmeticMask,
3032 Division = 1 | ArithmeticMask,
3033 Modulus = 2 | ArithmeticMask,
3034 Addition = 3 | ArithmeticMask | AdditionMask,
3035 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3037 LeftShift = 5 | ShiftMask,
3038 RightShift = 6 | ShiftMask,
3040 LessThan = 7 | ComparisonMask | RelationalMask,
3041 GreaterThan = 8 | ComparisonMask | RelationalMask,
3042 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3043 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3044 Equality = 11 | ComparisonMask | EqualityMask,
3045 Inequality = 12 | ComparisonMask | EqualityMask,
3047 BitwiseAnd = 13 | BitwiseMask,
3048 ExclusiveOr = 14 | BitwiseMask,
3049 BitwiseOr = 15 | BitwiseMask,
3051 LogicalAnd = 16 | LogicalMask,
3052 LogicalOr = 17 | LogicalMask,
3057 ValuesOnlyMask = ArithmeticMask - 1,
3058 ArithmeticMask = 1 << 5,
3060 ComparisonMask = 1 << 7,
3061 EqualityMask = 1 << 8,
3062 BitwiseMask = 1 << 9,
3063 LogicalMask = 1 << 10,
3064 AdditionMask = 1 << 11,
3065 SubtractionMask = 1 << 12,
3066 RelationalMask = 1 << 13,
3068 DecomposedMask = 1 << 19,
3069 NullableMask = 1 << 20,
3079 readonly Operator oper;
3080 Expression left, right;
3082 ConvCast.Mode enum_conversion;
3084 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3085 : this (oper, left, right)
3088 state |= State.Compound;
3091 public Binary (Operator oper, Expression left, Expression right)
3092 : this (oper, left, right, left.Location)
3096 public Binary (Operator oper, Expression left, Expression right, Location loc)
3106 public bool IsCompound {
3108 return (state & State.Compound) != 0;
3112 public Operator Oper {
3118 public Expression Left {
3124 public Expression Right {
3130 public override Location StartLocation {
3132 return left.StartLocation;
3139 /// Returns a stringified representation of the Operator
3141 string OperName (Operator oper)
3145 case Operator.Multiply:
3148 case Operator.Division:
3151 case Operator.Modulus:
3154 case Operator.Addition:
3157 case Operator.Subtraction:
3160 case Operator.LeftShift:
3163 case Operator.RightShift:
3166 case Operator.LessThan:
3169 case Operator.GreaterThan:
3172 case Operator.LessThanOrEqual:
3175 case Operator.GreaterThanOrEqual:
3178 case Operator.Equality:
3181 case Operator.Inequality:
3184 case Operator.BitwiseAnd:
3187 case Operator.BitwiseOr:
3190 case Operator.ExclusiveOr:
3193 case Operator.LogicalOr:
3196 case Operator.LogicalAnd:
3200 s = oper.ToString ();
3210 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3212 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3215 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3217 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3221 l = left.Type.GetSignatureForError ();
3222 r = right.Type.GetSignatureForError ();
3224 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3228 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3230 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3233 public override void FlowAnalysis (FlowAnalysisContext fc)
3236 // Optimized version when on-true/on-false data are not needed
3238 if ((oper & Operator.LogicalMask) == 0) {
3239 left.FlowAnalysis (fc);
3240 right.FlowAnalysis (fc);
3244 left.FlowAnalysisConditional (fc);
3245 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3246 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3248 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3249 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3250 right.FlowAnalysisConditional (fc);
3252 if (oper == Operator.LogicalOr)
3253 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3255 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3258 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3260 if ((oper & Operator.LogicalMask) == 0) {
3261 base.FlowAnalysisConditional (fc);
3265 left.FlowAnalysisConditional (fc);
3266 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3267 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3269 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3270 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3271 right.FlowAnalysisConditional (fc);
3273 var lc = left as Constant;
3274 if (oper == Operator.LogicalOr) {
3275 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3276 if (lc != null && lc.IsDefaultValue)
3277 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3279 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3281 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3282 if (lc != null && !lc.IsDefaultValue)
3283 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3285 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3290 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3292 string GetOperatorExpressionTypeName ()
3295 case Operator.Addition:
3296 return IsCompound ? "AddAssign" : "Add";
3297 case Operator.BitwiseAnd:
3298 return IsCompound ? "AndAssign" : "And";
3299 case Operator.BitwiseOr:
3300 return IsCompound ? "OrAssign" : "Or";
3301 case Operator.Division:
3302 return IsCompound ? "DivideAssign" : "Divide";
3303 case Operator.ExclusiveOr:
3304 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3305 case Operator.Equality:
3307 case Operator.GreaterThan:
3308 return "GreaterThan";
3309 case Operator.GreaterThanOrEqual:
3310 return "GreaterThanOrEqual";
3311 case Operator.Inequality:
3313 case Operator.LeftShift:
3314 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3315 case Operator.LessThan:
3317 case Operator.LessThanOrEqual:
3318 return "LessThanOrEqual";
3319 case Operator.LogicalAnd:
3321 case Operator.LogicalOr:
3323 case Operator.Modulus:
3324 return IsCompound ? "ModuloAssign" : "Modulo";
3325 case Operator.Multiply:
3326 return IsCompound ? "MultiplyAssign" : "Multiply";
3327 case Operator.RightShift:
3328 return IsCompound ? "RightShiftAssign" : "RightShift";
3329 case Operator.Subtraction:
3330 return IsCompound ? "SubtractAssign" : "Subtract";
3332 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3336 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3339 case Operator.Addition:
3340 return CSharp.Operator.OpType.Addition;
3341 case Operator.BitwiseAnd:
3342 case Operator.LogicalAnd:
3343 return CSharp.Operator.OpType.BitwiseAnd;
3344 case Operator.BitwiseOr:
3345 case Operator.LogicalOr:
3346 return CSharp.Operator.OpType.BitwiseOr;
3347 case Operator.Division:
3348 return CSharp.Operator.OpType.Division;
3349 case Operator.Equality:
3350 return CSharp.Operator.OpType.Equality;
3351 case Operator.ExclusiveOr:
3352 return CSharp.Operator.OpType.ExclusiveOr;
3353 case Operator.GreaterThan:
3354 return CSharp.Operator.OpType.GreaterThan;
3355 case Operator.GreaterThanOrEqual:
3356 return CSharp.Operator.OpType.GreaterThanOrEqual;
3357 case Operator.Inequality:
3358 return CSharp.Operator.OpType.Inequality;
3359 case Operator.LeftShift:
3360 return CSharp.Operator.OpType.LeftShift;
3361 case Operator.LessThan:
3362 return CSharp.Operator.OpType.LessThan;
3363 case Operator.LessThanOrEqual:
3364 return CSharp.Operator.OpType.LessThanOrEqual;
3365 case Operator.Modulus:
3366 return CSharp.Operator.OpType.Modulus;
3367 case Operator.Multiply:
3368 return CSharp.Operator.OpType.Multiply;
3369 case Operator.RightShift:
3370 return CSharp.Operator.OpType.RightShift;
3371 case Operator.Subtraction:
3372 return CSharp.Operator.OpType.Subtraction;
3374 throw new InternalErrorException (op.ToString ());
3378 public override bool ContainsEmitWithAwait ()
3380 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3383 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3388 case Operator.Multiply:
3389 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3390 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3391 opcode = OpCodes.Mul_Ovf;
3392 else if (!IsFloat (l))
3393 opcode = OpCodes.Mul_Ovf_Un;
3395 opcode = OpCodes.Mul;
3397 opcode = OpCodes.Mul;
3401 case Operator.Division:
3403 opcode = OpCodes.Div_Un;
3405 opcode = OpCodes.Div;
3408 case Operator.Modulus:
3410 opcode = OpCodes.Rem_Un;
3412 opcode = OpCodes.Rem;
3415 case Operator.Addition:
3416 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3417 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3418 opcode = OpCodes.Add_Ovf;
3419 else if (!IsFloat (l))
3420 opcode = OpCodes.Add_Ovf_Un;
3422 opcode = OpCodes.Add;
3424 opcode = OpCodes.Add;
3427 case Operator.Subtraction:
3428 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3429 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3430 opcode = OpCodes.Sub_Ovf;
3431 else if (!IsFloat (l))
3432 opcode = OpCodes.Sub_Ovf_Un;
3434 opcode = OpCodes.Sub;
3436 opcode = OpCodes.Sub;
3439 case Operator.RightShift:
3440 if (!(right is IntConstant)) {
3441 ec.EmitInt (GetShiftMask (l));
3442 ec.Emit (OpCodes.And);
3446 opcode = OpCodes.Shr_Un;
3448 opcode = OpCodes.Shr;
3451 case Operator.LeftShift:
3452 if (!(right is IntConstant)) {
3453 ec.EmitInt (GetShiftMask (l));
3454 ec.Emit (OpCodes.And);
3457 opcode = OpCodes.Shl;
3460 case Operator.Equality:
3461 opcode = OpCodes.Ceq;
3464 case Operator.Inequality:
3465 ec.Emit (OpCodes.Ceq);
3468 opcode = OpCodes.Ceq;
3471 case Operator.LessThan:
3473 opcode = OpCodes.Clt_Un;
3475 opcode = OpCodes.Clt;
3478 case Operator.GreaterThan:
3480 opcode = OpCodes.Cgt_Un;
3482 opcode = OpCodes.Cgt;
3485 case Operator.LessThanOrEqual:
3486 if (IsUnsigned (l) || IsFloat (l))
3487 ec.Emit (OpCodes.Cgt_Un);
3489 ec.Emit (OpCodes.Cgt);
3492 opcode = OpCodes.Ceq;
3495 case Operator.GreaterThanOrEqual:
3496 if (IsUnsigned (l) || IsFloat (l))
3497 ec.Emit (OpCodes.Clt_Un);
3499 ec.Emit (OpCodes.Clt);
3503 opcode = OpCodes.Ceq;
3506 case Operator.BitwiseOr:
3507 opcode = OpCodes.Or;
3510 case Operator.BitwiseAnd:
3511 opcode = OpCodes.And;
3514 case Operator.ExclusiveOr:
3515 opcode = OpCodes.Xor;
3519 throw new InternalErrorException (oper.ToString ());
3525 static int GetShiftMask (TypeSpec type)
3527 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3530 static bool IsUnsigned (TypeSpec t)
3532 switch (t.BuiltinType) {
3533 case BuiltinTypeSpec.Type.Char:
3534 case BuiltinTypeSpec.Type.UInt:
3535 case BuiltinTypeSpec.Type.ULong:
3536 case BuiltinTypeSpec.Type.UShort:
3537 case BuiltinTypeSpec.Type.Byte:
3544 static bool IsFloat (TypeSpec t)
3546 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3549 public Expression ResolveOperator (ResolveContext rc)
3551 eclass = ExprClass.Value;
3553 TypeSpec l = left.Type;
3554 TypeSpec r = right.Type;
3556 bool primitives_only = false;
3559 // Handles predefined primitive types
3561 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3562 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3563 if ((oper & Operator.ShiftMask) == 0) {
3564 if (!DoBinaryOperatorPromotion (rc))
3567 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3571 if (l.IsPointer || r.IsPointer)
3572 return ResolveOperatorPointer (rc, l, r);
3575 expr = ResolveUserOperator (rc, left, right);
3580 bool lenum = l.IsEnum;
3581 bool renum = r.IsEnum;
3582 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3586 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3587 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3592 if ((oper & Operator.BitwiseMask) != 0) {
3593 expr = EmptyCast.Create (expr, type);
3594 enum_conversion = GetEnumResultCast (type);
3596 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3597 expr = OptimizeAndOperation (expr);
3601 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3602 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3605 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3606 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3610 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3613 // We cannot break here there is also Enum + String possible match
3614 // which is not ambiguous with predefined enum operators
3617 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3618 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3622 } else if (l.IsDelegate || r.IsDelegate) {
3626 expr = ResolveOperatorDelegate (rc, l, r);
3628 // TODO: Can this be ambiguous
3636 // Equality operators are more complicated
3638 if ((oper & Operator.EqualityMask) != 0) {
3639 return ResolveEquality (rc, l, r, primitives_only);
3642 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3646 if (primitives_only)
3650 // Lifted operators have lower priority
3652 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3655 static bool IsEnumOrNullableEnum (TypeSpec type)
3657 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3661 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3662 // if 'left' is not an enumeration constant, create one from the type of 'right'
3663 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3666 case Operator.BitwiseOr:
3667 case Operator.BitwiseAnd:
3668 case Operator.ExclusiveOr:
3669 case Operator.Equality:
3670 case Operator.Inequality:
3671 case Operator.LessThan:
3672 case Operator.LessThanOrEqual:
3673 case Operator.GreaterThan:
3674 case Operator.GreaterThanOrEqual:
3675 if (left.Type.IsEnum)
3678 if (left.IsZeroInteger)
3679 return left.Reduce (ec, right.Type);
3683 case Operator.Addition:
3684 case Operator.Subtraction:
3687 case Operator.Multiply:
3688 case Operator.Division:
3689 case Operator.Modulus:
3690 case Operator.LeftShift:
3691 case Operator.RightShift:
3692 if (right.Type.IsEnum || left.Type.IsEnum)
3701 // The `|' operator used on types which were extended is dangerous
3703 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3705 OpcodeCast lcast = left as OpcodeCast;
3706 if (lcast != null) {
3707 if (IsUnsigned (lcast.UnderlyingType))
3711 OpcodeCast rcast = right as OpcodeCast;
3712 if (rcast != null) {
3713 if (IsUnsigned (rcast.UnderlyingType))
3717 if (lcast == null && rcast == null)
3720 // FIXME: consider constants
3722 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3723 ec.Report.Warning (675, 3, loc,
3724 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3725 ltype.GetSignatureForError ());
3728 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3730 return new PredefinedOperator[] {
3732 // Pointer arithmetic:
3734 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3735 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3736 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3737 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3739 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3740 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3741 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3742 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3745 // T* operator + (int y, T* x);
3746 // T* operator + (uint y, T *x);
3747 // T* operator + (long y, T *x);
3748 // T* operator + (ulong y, T *x);
3750 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3751 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3752 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3753 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3756 // long operator - (T* x, T *y)
3758 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3762 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3764 TypeSpec bool_type = types.Bool;
3767 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3768 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3769 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3770 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3771 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3772 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3773 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3775 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3776 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3777 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3778 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3779 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3780 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3781 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3783 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3784 // Remaining string operators are in lifted tables
3786 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3788 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3789 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3790 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3794 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3796 var types = module.Compiler.BuiltinTypes;
3799 // Not strictly lifted but need to be in second group otherwise expressions like
3800 // int + null would resolve to +(object, string) instead of +(int?, int?)
3802 var string_operators = new [] {
3803 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3804 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3807 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3808 if (nullable == null)
3809 return string_operators;
3811 var bool_type = types.Bool;
3813 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3814 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3815 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3816 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3817 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3818 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3819 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3820 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3823 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3824 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3825 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3826 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3827 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3828 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3829 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3831 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3832 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3833 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3834 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3835 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3836 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3837 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3839 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3841 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3842 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3843 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3845 string_operators [0],
3846 string_operators [1]
3850 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3852 TypeSpec bool_type = types.Bool;
3855 new PredefinedEqualityOperator (types.String, bool_type),
3856 new PredefinedEqualityOperator (types.Delegate, bool_type),
3857 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3858 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3859 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3860 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3861 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3862 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3863 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3864 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3868 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3870 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3872 if (nullable == null)
3873 return new PredefinedOperator [0];
3875 var types = module.Compiler.BuiltinTypes;
3876 var bool_type = types.Bool;
3877 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3878 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3879 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3880 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3881 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3882 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3883 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3884 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3887 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3888 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3889 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3890 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3891 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3892 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3893 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3894 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3899 // 7.2.6.2 Binary numeric promotions
3901 bool DoBinaryOperatorPromotion (ResolveContext rc)
3903 TypeSpec ltype = left.Type;
3904 if (ltype.IsNullableType) {
3905 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3909 // This is numeric promotion code only
3911 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3914 TypeSpec rtype = right.Type;
3915 if (rtype.IsNullableType) {
3916 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3919 var lb = ltype.BuiltinType;
3920 var rb = rtype.BuiltinType;
3924 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3925 type = rc.BuiltinTypes.Decimal;
3926 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3927 type = rc.BuiltinTypes.Double;
3928 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3929 type = rc.BuiltinTypes.Float;
3930 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3931 type = rc.BuiltinTypes.ULong;
3933 if (IsSignedType (lb)) {
3934 expr = ConvertSignedConstant (left, type);
3938 } else if (IsSignedType (rb)) {
3939 expr = ConvertSignedConstant (right, type);
3945 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3946 type = rc.BuiltinTypes.Long;
3947 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3948 type = rc.BuiltinTypes.UInt;
3950 if (IsSignedType (lb)) {
3951 expr = ConvertSignedConstant (left, type);
3953 type = rc.BuiltinTypes.Long;
3954 } else if (IsSignedType (rb)) {
3955 expr = ConvertSignedConstant (right, type);
3957 type = rc.BuiltinTypes.Long;
3960 type = rc.BuiltinTypes.Int;
3963 if (ltype != type) {
3964 expr = PromoteExpression (rc, left, type);
3971 if (rtype != type) {
3972 expr = PromoteExpression (rc, right, type);
3982 static bool IsSignedType (BuiltinTypeSpec.Type type)
3985 case BuiltinTypeSpec.Type.Int:
3986 case BuiltinTypeSpec.Type.Short:
3987 case BuiltinTypeSpec.Type.SByte:
3988 case BuiltinTypeSpec.Type.Long:
3995 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3997 var c = expr as Constant;
4001 return c.ConvertImplicitly (type);
4004 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4006 if (expr.Type.IsNullableType) {
4007 return Convert.ImplicitConversionStandard (rc, expr,
4008 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4011 var c = expr as Constant;
4013 return c.ConvertImplicitly (type);
4015 return Convert.ImplicitNumericConversion (expr, type);
4018 protected override Expression DoResolve (ResolveContext ec)
4023 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4024 left = ((ParenthesizedExpression) left).Expr;
4025 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4029 if (left.eclass == ExprClass.Type) {
4030 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4034 left = left.Resolve (ec);
4039 right = right.Resolve (ec);
4043 Constant lc = left as Constant;
4044 Constant rc = right as Constant;
4046 // The conversion rules are ignored in enum context but why
4047 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4048 lc = EnumLiftUp (ec, lc, rc);
4050 rc = EnumLiftUp (ec, rc, lc);
4053 if (rc != null && lc != null) {
4054 int prev_e = ec.Report.Errors;
4055 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4056 if (e != null || ec.Report.Errors != prev_e)
4060 // Comparison warnings
4061 if ((oper & Operator.ComparisonMask) != 0) {
4062 if (left.Equals (right)) {
4063 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4065 CheckOutOfRangeComparison (ec, lc, right.Type);
4066 CheckOutOfRangeComparison (ec, rc, left.Type);
4069 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4070 return DoResolveDynamic (ec);
4072 return DoResolveCore (ec, left, right);
4075 Expression DoResolveDynamic (ResolveContext rc)
4078 var rt = right.Type;
4079 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4080 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4081 Error_OperatorCannotBeApplied (rc, left, right);
4088 // Special handling for logical boolean operators which require rhs not to be
4089 // evaluated based on lhs value
4091 if ((oper & Operator.LogicalMask) != 0) {
4092 Expression cond_left, cond_right, expr;
4094 args = new Arguments (2);
4096 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4097 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4099 var cond_args = new Arguments (1);
4100 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4103 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4104 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4106 left = temp.CreateReferenceExpression (rc, loc);
4107 if (oper == Operator.LogicalAnd) {
4108 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4111 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4115 args.Add (new Argument (left));
4116 args.Add (new Argument (right));
4117 cond_right = new DynamicExpressionStatement (this, args, loc);
4119 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4121 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4122 rc.Report.Error (7083, left.Location,
4123 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4124 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4128 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4129 args.Add (new Argument (right));
4130 right = new DynamicExpressionStatement (this, args, loc);
4133 // bool && dynamic => (temp = left) ? temp && right : temp;
4134 // bool || dynamic => (temp = left) ? temp : temp || right;
4136 if (oper == Operator.LogicalAnd) {
4138 cond_right = temp.CreateReferenceExpression (rc, loc);
4140 cond_left = temp.CreateReferenceExpression (rc, loc);
4144 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4147 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4150 args = new Arguments (2);
4151 args.Add (new Argument (left));
4152 args.Add (new Argument (right));
4153 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4156 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4158 Expression expr = ResolveOperator (ec);
4160 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4162 if (left == null || right == null)
4163 throw new InternalErrorException ("Invalid conversion");
4165 if (oper == Operator.BitwiseOr)
4166 CheckBitwiseOrOnSignExtended (ec);
4171 public override SLE.Expression MakeExpression (BuilderContext ctx)
4173 return MakeExpression (ctx, left, right);
4176 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4178 var le = left.MakeExpression (ctx);
4179 var re = right.MakeExpression (ctx);
4180 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4183 case Operator.Addition:
4184 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4185 case Operator.BitwiseAnd:
4186 return SLE.Expression.And (le, re);
4187 case Operator.BitwiseOr:
4188 return SLE.Expression.Or (le, re);
4189 case Operator.Division:
4190 return SLE.Expression.Divide (le, re);
4191 case Operator.Equality:
4192 return SLE.Expression.Equal (le, re);
4193 case Operator.ExclusiveOr:
4194 return SLE.Expression.ExclusiveOr (le, re);
4195 case Operator.GreaterThan:
4196 return SLE.Expression.GreaterThan (le, re);
4197 case Operator.GreaterThanOrEqual:
4198 return SLE.Expression.GreaterThanOrEqual (le, re);
4199 case Operator.Inequality:
4200 return SLE.Expression.NotEqual (le, re);
4201 case Operator.LeftShift:
4202 return SLE.Expression.LeftShift (le, re);
4203 case Operator.LessThan:
4204 return SLE.Expression.LessThan (le, re);
4205 case Operator.LessThanOrEqual:
4206 return SLE.Expression.LessThanOrEqual (le, re);
4207 case Operator.LogicalAnd:
4208 return SLE.Expression.AndAlso (le, re);
4209 case Operator.LogicalOr:
4210 return SLE.Expression.OrElse (le, re);
4211 case Operator.Modulus:
4212 return SLE.Expression.Modulo (le, re);
4213 case Operator.Multiply:
4214 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4215 case Operator.RightShift:
4216 return SLE.Expression.RightShift (le, re);
4217 case Operator.Subtraction:
4218 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4220 throw new NotImplementedException (oper.ToString ());
4225 // D operator + (D x, D y)
4226 // D operator - (D x, D y)
4228 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4230 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4232 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4233 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4238 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4239 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4249 MethodSpec method = null;
4250 Arguments args = new Arguments (2);
4251 args.Add (new Argument (left));
4252 args.Add (new Argument (right));
4254 if (oper == Operator.Addition) {
4255 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4256 } else if (oper == Operator.Subtraction) {
4257 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4261 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4263 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4264 return new ClassCast (expr, l);
4268 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4270 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4273 // bool operator == (E x, E y);
4274 // bool operator != (E x, E y);
4275 // bool operator < (E x, E y);
4276 // bool operator > (E x, E y);
4277 // bool operator <= (E x, E y);
4278 // bool operator >= (E x, E y);
4280 // E operator & (E x, E y);
4281 // E operator | (E x, E y);
4282 // E operator ^ (E x, E y);
4285 if ((oper & Operator.ComparisonMask) != 0) {
4286 type = rc.BuiltinTypes.Bool;
4292 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4298 if (ltype == rtype) {
4302 var lifted = new Nullable.LiftedBinaryOperator (this);
4304 lifted.Right = right;
4305 return lifted.Resolve (rc);
4308 if (renum && !ltype.IsNullableType) {
4309 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4314 } else if (lenum && !rtype.IsNullableType) {
4315 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4323 // Now try lifted version of predefined operator
4325 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4326 if (nullable_type != null) {
4327 if (renum && !ltype.IsNullableType) {
4328 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4330 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4333 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4336 if ((oper & Operator.BitwiseMask) != 0)
4340 if ((oper & Operator.BitwiseMask) != 0)
4341 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4343 return CreateLiftedValueTypeResult (rc, rtype);
4347 var lifted = new Nullable.LiftedBinaryOperator (this);
4349 lifted.Right = right;
4350 return lifted.Resolve (rc);
4352 } else if (lenum && !rtype.IsNullableType) {
4353 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4355 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4358 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4361 if ((oper & Operator.BitwiseMask) != 0)
4365 if ((oper & Operator.BitwiseMask) != 0)
4366 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4368 return CreateLiftedValueTypeResult (rc, ltype);
4372 var lifted = new Nullable.LiftedBinaryOperator (this);
4374 lifted.Right = expr;
4375 return lifted.Resolve (rc);
4377 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4378 Nullable.Unwrap unwrap = null;
4379 if (left.IsNull || right.IsNull) {
4380 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4381 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4383 if ((oper & Operator.RelationalMask) != 0)
4384 return CreateLiftedValueTypeResult (rc, rtype);
4386 if ((oper & Operator.BitwiseMask) != 0)
4387 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4390 return CreateLiftedValueTypeResult (rc, left.Type);
4392 // Equality operators are valid between E? and null
4394 unwrap = new Nullable.Unwrap (right);
4396 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4402 var lifted = new Nullable.LiftedBinaryOperator (this);
4404 lifted.Right = right;
4405 lifted.UnwrapRight = unwrap;
4406 return lifted.Resolve (rc);
4408 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4409 Nullable.Unwrap unwrap = null;
4410 if (right.IsNull || left.IsNull) {
4411 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4412 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4414 if ((oper & Operator.RelationalMask) != 0)
4415 return CreateLiftedValueTypeResult (rc, ltype);
4417 if ((oper & Operator.BitwiseMask) != 0)
4418 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4421 return CreateLiftedValueTypeResult (rc, right.Type);
4423 // Equality operators are valid between E? and null
4425 unwrap = new Nullable.Unwrap (left);
4427 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4433 var lifted = new Nullable.LiftedBinaryOperator (this);
4435 lifted.UnwrapLeft = unwrap;
4436 lifted.Right = expr;
4437 return lifted.Resolve (rc);
4445 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4447 TypeSpec underlying_type;
4448 if (expr.Type.IsNullableType) {
4449 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4451 underlying_type = EnumSpec.GetUnderlyingType (nt);
4453 underlying_type = nt;
4454 } else if (expr.Type.IsEnum) {
4455 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4457 underlying_type = expr.Type;
4460 switch (underlying_type.BuiltinType) {
4461 case BuiltinTypeSpec.Type.SByte:
4462 case BuiltinTypeSpec.Type.Byte:
4463 case BuiltinTypeSpec.Type.Short:
4464 case BuiltinTypeSpec.Type.UShort:
4465 underlying_type = rc.BuiltinTypes.Int;
4469 if (expr.Type.IsNullableType || liftType)
4470 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4472 if (expr.Type == underlying_type)
4475 return EmptyCast.Create (expr, underlying_type);
4478 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4481 // U operator - (E e, E f)
4482 // E operator - (E e, U x) // Internal decomposition operator
4483 // E operator - (U x, E e) // Internal decomposition operator
4485 // E operator + (E e, U x)
4486 // E operator + (U x, E e)
4495 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4501 if (!enum_type.IsNullableType) {
4502 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4504 if (oper == Operator.Subtraction)
4505 expr = ConvertEnumSubtractionResult (rc, expr);
4507 expr = ConvertEnumAdditionalResult (expr, enum_type);
4509 enum_conversion = GetEnumResultCast (expr.Type);
4514 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4517 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4519 if (oper == Operator.Subtraction)
4520 expr = ConvertEnumSubtractionResult (rc, expr);
4522 expr = ConvertEnumAdditionalResult (expr, enum_type);
4524 enum_conversion = GetEnumResultCast (expr.Type);
4530 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4532 return EmptyCast.Create (expr, enumType);
4535 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4538 // Enumeration subtraction has different result type based on
4541 TypeSpec result_type;
4542 if (left.Type == right.Type) {
4543 var c = right as EnumConstant;
4544 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4546 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4547 // E which is not what expressions E - 1 or 0 - E return
4549 result_type = left.Type;
4551 result_type = left.Type.IsNullableType ?
4552 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4553 EnumSpec.GetUnderlyingType (left.Type);
4556 if (IsEnumOrNullableEnum (left.Type)) {
4557 result_type = left.Type;
4559 result_type = right.Type;
4562 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4563 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4566 return EmptyCast.Create (expr, result_type);
4569 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4571 if (type.IsNullableType)
4572 type = Nullable.NullableInfo.GetUnderlyingType (type);
4575 type = EnumSpec.GetUnderlyingType (type);
4577 switch (type.BuiltinType) {
4578 case BuiltinTypeSpec.Type.SByte:
4579 return ConvCast.Mode.I4_I1;
4580 case BuiltinTypeSpec.Type.Byte:
4581 return ConvCast.Mode.I4_U1;
4582 case BuiltinTypeSpec.Type.Short:
4583 return ConvCast.Mode.I4_I2;
4584 case BuiltinTypeSpec.Type.UShort:
4585 return ConvCast.Mode.I4_U2;
4592 // Equality operators rules
4594 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4597 type = ec.BuiltinTypes.Bool;
4598 bool no_arg_conv = false;
4600 if (!primitives_only) {
4603 // a, Both operands are reference-type values or the value null
4604 // b, One operand is a value of type T where T is a type-parameter and
4605 // the other operand is the value null. Furthermore T does not have the
4606 // value type constraint
4608 // LAMESPEC: Very confusing details in the specification, basically any
4609 // reference like type-parameter is allowed
4611 var tparam_l = l as TypeParameterSpec;
4612 var tparam_r = r as TypeParameterSpec;
4613 if (tparam_l != null) {
4614 if (right is NullLiteral) {
4615 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4618 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4622 if (!tparam_l.IsReferenceType)
4625 l = tparam_l.GetEffectiveBase ();
4626 left = new BoxedCast (left, l);
4627 } else if (left is NullLiteral && tparam_r == null) {
4628 if (TypeSpec.IsReferenceType (r))
4631 if (r.Kind == MemberKind.InternalCompilerType)
4635 if (tparam_r != null) {
4636 if (left is NullLiteral) {
4637 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4640 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4644 if (!tparam_r.IsReferenceType)
4647 r = tparam_r.GetEffectiveBase ();
4648 right = new BoxedCast (right, r);
4649 } else if (right is NullLiteral) {
4650 if (TypeSpec.IsReferenceType (l))
4653 if (l.Kind == MemberKind.InternalCompilerType)
4658 // LAMESPEC: method groups can be compared when they convert to other side delegate
4661 if (right.eclass == ExprClass.MethodGroup) {
4662 result = Convert.ImplicitConversion (ec, right, l, loc);
4668 } else if (r.IsDelegate && l != r) {
4671 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4672 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4679 no_arg_conv = l == r && !l.IsStruct;
4684 // bool operator != (string a, string b)
4685 // bool operator == (string a, string b)
4687 // bool operator != (Delegate a, Delegate b)
4688 // bool operator == (Delegate a, Delegate b)
4690 // bool operator != (bool a, bool b)
4691 // bool operator == (bool a, bool b)
4693 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4694 // they implement an implicit conversion to any of types above. This does
4695 // not apply when both operands are of same reference type
4697 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4698 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4703 // Now try lifted version of predefined operators
4705 if (no_arg_conv && !l.IsNullableType) {
4707 // Optimizes cases which won't match
4710 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4716 // The == and != operators permit one operand to be a value of a nullable
4717 // type and the other to be the null literal, even if no predefined or user-defined
4718 // operator (in unlifted or lifted form) exists for the operation.
4720 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4721 var lifted = new Nullable.LiftedBinaryOperator (this);
4723 lifted.Right = right;
4724 return lifted.Resolve (ec);
4729 // bool operator != (object a, object b)
4730 // bool operator == (object a, object b)
4732 // An explicit reference conversion exists from the
4733 // type of either operand to the type of the other operand.
4736 // Optimize common path
4738 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4741 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4742 !Convert.ExplicitReferenceConversionExists (r, l))
4745 // Reject allowed explicit conversions like int->object
4746 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4749 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4750 ec.Report.Warning (253, 2, loc,
4751 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4752 l.GetSignatureForError ());
4754 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4755 ec.Report.Warning (252, 2, loc,
4756 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4757 r.GetSignatureForError ());
4763 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4766 // bool operator == (void* x, void* y);
4767 // bool operator != (void* x, void* y);
4768 // bool operator < (void* x, void* y);
4769 // bool operator > (void* x, void* y);
4770 // bool operator <= (void* x, void* y);
4771 // bool operator >= (void* x, void* y);
4773 if ((oper & Operator.ComparisonMask) != 0) {
4776 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4783 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4789 type = ec.BuiltinTypes.Bool;
4793 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4797 // Build-in operators method overloading
4799 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4801 PredefinedOperator best_operator = null;
4802 TypeSpec l = left.Type;
4803 TypeSpec r = right.Type;
4804 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4806 foreach (PredefinedOperator po in operators) {
4807 if ((po.OperatorsMask & oper_mask) == 0)
4810 if (primitives_only) {
4811 if (!po.IsPrimitiveApplicable (l, r))
4814 if (!po.IsApplicable (ec, left, right))
4818 if (best_operator == null) {
4820 if (primitives_only)
4826 best_operator = po.ResolveBetterOperator (ec, best_operator);
4828 if (best_operator == null) {
4829 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4830 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4837 if (best_operator == null)
4840 return best_operator.ConvertResult (ec, this);
4844 // Optimize & constant expressions with 0 value
4846 Expression OptimizeAndOperation (Expression expr)
4848 Constant rc = right as Constant;
4849 Constant lc = left as Constant;
4850 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4852 // The result is a constant with side-effect
4854 Constant side_effect = rc == null ?
4855 new SideEffectConstant (lc, right, loc) :
4856 new SideEffectConstant (rc, left, loc);
4858 return ReducedExpression.Create (side_effect, expr);
4865 // Value types can be compared with the null literal because of the lifting
4866 // language rules. However the result is always true or false.
4868 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4870 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4871 type = rc.BuiltinTypes.Bool;
4875 // FIXME: Handle side effect constants
4876 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4878 if ((Oper & Operator.EqualityMask) != 0) {
4879 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4880 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4882 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4883 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4890 // Performs user-operator overloading
4892 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4894 Expression oper_expr;
4896 var op = ConvertBinaryToUserOperator (oper);
4898 if (l.IsNullableType)
4899 l = Nullable.NullableInfo.GetUnderlyingType (l);
4901 if (r.IsNullableType)
4902 r = Nullable.NullableInfo.GetUnderlyingType (r);
4904 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4905 IList<MemberSpec> right_operators = null;
4908 right_operators = MemberCache.GetUserOperator (r, op, false);
4909 if (right_operators == null && left_operators == null)
4911 } else if (left_operators == null) {
4915 Arguments args = new Arguments (2);
4916 Argument larg = new Argument (left);
4918 Argument rarg = new Argument (right);
4922 // User-defined operator implementations always take precedence
4923 // over predefined operator implementations
4925 if (left_operators != null && right_operators != null) {
4926 left_operators = CombineUserOperators (left_operators, right_operators);
4927 } else if (right_operators != null) {
4928 left_operators = right_operators;
4931 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4932 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4934 var res = new OverloadResolver (left_operators, restr, loc);
4936 var oper_method = res.ResolveOperator (rc, ref args);
4937 if (oper_method == null) {
4939 // Logical && and || cannot be lifted
4941 if ((oper & Operator.LogicalMask) != 0)
4945 // Apply lifted user operators only for liftable types. Implicit conversion
4946 // to nullable types is not allowed
4948 if (!IsLiftedOperatorApplicable ())
4951 // TODO: Cache the result in module container
4952 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4953 if (lifted_methods == null)
4956 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4958 oper_method = res.ResolveOperator (rc, ref args);
4959 if (oper_method == null)
4962 MethodSpec best_original = null;
4963 foreach (MethodSpec ms in left_operators) {
4964 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4970 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4972 // Expression trees use lifted notation in this case
4974 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4975 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4978 var ptypes = best_original.Parameters.Types;
4980 if (left.IsNull || right.IsNull) {
4982 // The lifted operator produces a null value if one or both operands are null
4984 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4985 type = oper_method.ReturnType;
4986 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4990 // The lifted operator produces the value false if one or both operands are null for
4991 // relational operators.
4993 if ((oper & Operator.RelationalMask) != 0) {
4995 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4996 // because return type is actually bool
4998 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5001 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5002 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5006 type = oper_method.ReturnType;
5007 var lifted = new Nullable.LiftedBinaryOperator (this);
5008 lifted.UserOperator = best_original;
5010 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5011 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5014 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5015 lifted.UnwrapRight = new Nullable.Unwrap (right);
5018 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5019 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5021 return lifted.Resolve (rc);
5024 if ((oper & Operator.LogicalMask) != 0) {
5025 // TODO: CreateExpressionTree is allocated every time
5026 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5027 oper == Operator.LogicalAnd, loc).Resolve (rc);
5029 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5032 this.left = larg.Expr;
5033 this.right = rarg.Expr;
5038 bool IsLiftedOperatorApplicable ()
5040 if (left.Type.IsNullableType) {
5041 if ((oper & Operator.EqualityMask) != 0)
5042 return !right.IsNull;
5047 if (right.Type.IsNullableType) {
5048 if ((oper & Operator.EqualityMask) != 0)
5049 return !left.IsNull;
5054 if (TypeSpec.IsValueType (left.Type))
5055 return right.IsNull;
5057 if (TypeSpec.IsValueType (right.Type))
5063 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5065 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5066 if (nullable_type == null)
5070 // Lifted operators permit predefined and user-defined operators that operate
5071 // on non-nullable value types to also be used with nullable forms of those types.
5072 // Lifted operators are constructed from predefined and user-defined operators
5073 // that meet certain requirements
5075 List<MemberSpec> lifted = null;
5076 foreach (MethodSpec oper in operators) {
5078 if ((Oper & Operator.ComparisonMask) != 0) {
5080 // Result type must be of type bool for lifted comparison operators
5082 rt = oper.ReturnType;
5083 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5086 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5092 var ptypes = oper.Parameters.Types;
5093 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5097 // LAMESPEC: I am not sure why but for equality operators to be lifted
5098 // both types have to match
5100 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5104 lifted = new List<MemberSpec> ();
5107 // The lifted form is constructed by adding a single ? modifier to each operand and
5108 // result type except for comparison operators where return type is bool
5111 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5113 var parameters = ParametersCompiled.CreateFullyResolved (
5114 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5115 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5117 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5118 rt, parameters, oper.Modifiers);
5120 lifted.Add (lifted_op);
5127 // Merge two sets of user operators into one, they are mostly distinguish
5128 // except when they share base type and it contains an operator
5130 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5132 var combined = new List<MemberSpec> (left.Count + right.Count);
5133 combined.AddRange (left);
5134 foreach (var r in right) {
5136 foreach (var l in left) {
5137 if (l.DeclaringType == r.DeclaringType) {
5150 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5152 if (c is IntegralConstant || c is CharConstant) {
5154 c.ConvertExplicitly (true, type);
5155 } catch (OverflowException) {
5156 ec.Report.Warning (652, 2, loc,
5157 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5158 type.GetSignatureForError ());
5164 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5165 /// context of a conditional bool expression. This function will return
5166 /// false if it is was possible to use EmitBranchable, or true if it was.
5168 /// The expression's code is generated, and we will generate a branch to `target'
5169 /// if the resulting expression value is equal to isTrue
5171 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5173 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5174 left = left.EmitToField (ec);
5176 if ((oper & Operator.LogicalMask) == 0) {
5177 right = right.EmitToField (ec);
5182 // This is more complicated than it looks, but its just to avoid
5183 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5184 // but on top of that we want for == and != to use a special path
5185 // if we are comparing against null
5187 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5188 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5191 // put the constant on the rhs, for simplicity
5193 if (left is Constant) {
5194 Expression swap = right;
5200 // brtrue/brfalse works with native int only
5202 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5203 left.EmitBranchable (ec, target, my_on_true);
5206 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5207 // right is a boolean, and it's not 'false' => it is 'true'
5208 left.EmitBranchable (ec, target, !my_on_true);
5212 } else if (oper == Operator.LogicalAnd) {
5215 Label tests_end = ec.DefineLabel ();
5217 left.EmitBranchable (ec, tests_end, false);
5218 right.EmitBranchable (ec, target, true);
5219 ec.MarkLabel (tests_end);
5222 // This optimizes code like this
5223 // if (true && i > 4)
5225 if (!(left is Constant))
5226 left.EmitBranchable (ec, target, false);
5228 if (!(right is Constant))
5229 right.EmitBranchable (ec, target, false);
5234 } else if (oper == Operator.LogicalOr){
5236 left.EmitBranchable (ec, target, true);
5237 right.EmitBranchable (ec, target, true);
5240 Label tests_end = ec.DefineLabel ();
5241 left.EmitBranchable (ec, tests_end, true);
5242 right.EmitBranchable (ec, target, false);
5243 ec.MarkLabel (tests_end);
5248 } else if ((oper & Operator.ComparisonMask) == 0) {
5249 base.EmitBranchable (ec, target, on_true);
5256 TypeSpec t = left.Type;
5257 bool is_float = IsFloat (t);
5258 bool is_unsigned = is_float || IsUnsigned (t);
5261 case Operator.Equality:
5263 ec.Emit (OpCodes.Beq, target);
5265 ec.Emit (OpCodes.Bne_Un, target);
5268 case Operator.Inequality:
5270 ec.Emit (OpCodes.Bne_Un, target);
5272 ec.Emit (OpCodes.Beq, target);
5275 case Operator.LessThan:
5277 if (is_unsigned && !is_float)
5278 ec.Emit (OpCodes.Blt_Un, target);
5280 ec.Emit (OpCodes.Blt, target);
5283 ec.Emit (OpCodes.Bge_Un, target);
5285 ec.Emit (OpCodes.Bge, target);
5288 case Operator.GreaterThan:
5290 if (is_unsigned && !is_float)
5291 ec.Emit (OpCodes.Bgt_Un, target);
5293 ec.Emit (OpCodes.Bgt, target);
5296 ec.Emit (OpCodes.Ble_Un, target);
5298 ec.Emit (OpCodes.Ble, target);
5301 case Operator.LessThanOrEqual:
5303 if (is_unsigned && !is_float)
5304 ec.Emit (OpCodes.Ble_Un, target);
5306 ec.Emit (OpCodes.Ble, target);
5309 ec.Emit (OpCodes.Bgt_Un, target);
5311 ec.Emit (OpCodes.Bgt, target);
5315 case Operator.GreaterThanOrEqual:
5317 if (is_unsigned && !is_float)
5318 ec.Emit (OpCodes.Bge_Un, target);
5320 ec.Emit (OpCodes.Bge, target);
5323 ec.Emit (OpCodes.Blt_Un, target);
5325 ec.Emit (OpCodes.Blt, target);
5328 throw new InternalErrorException (oper.ToString ());
5332 public override void Emit (EmitContext ec)
5334 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5335 left = left.EmitToField (ec);
5337 if ((oper & Operator.LogicalMask) == 0) {
5338 right = right.EmitToField (ec);
5343 // Handle short-circuit operators differently
5346 if ((oper & Operator.LogicalMask) != 0) {
5347 Label load_result = ec.DefineLabel ();
5348 Label end = ec.DefineLabel ();
5350 bool is_or = oper == Operator.LogicalOr;
5351 left.EmitBranchable (ec, load_result, is_or);
5353 ec.Emit (OpCodes.Br_S, end);
5355 ec.MarkLabel (load_result);
5356 ec.EmitInt (is_or ? 1 : 0);
5362 // Optimize zero-based operations which cannot be optimized at expression level
5364 if (oper == Operator.Subtraction) {
5365 var lc = left as IntegralConstant;
5366 if (lc != null && lc.IsDefaultValue) {
5368 ec.Emit (OpCodes.Neg);
5373 EmitOperator (ec, left, right);
5376 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5381 EmitOperatorOpcode (ec, oper, left.Type, right);
5384 // Emit result enumerable conversion this way because it's quite complicated get it
5385 // to resolved tree because expression tree cannot see it.
5387 if (enum_conversion != 0)
5388 ConvCast.Emit (ec, enum_conversion);
5391 public override void EmitSideEffect (EmitContext ec)
5393 if ((oper & Operator.LogicalMask) != 0 ||
5394 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5395 base.EmitSideEffect (ec);
5397 left.EmitSideEffect (ec);
5398 right.EmitSideEffect (ec);
5402 public override Expression EmitToField (EmitContext ec)
5404 if ((oper & Operator.LogicalMask) == 0) {
5405 var await_expr = left as Await;
5406 if (await_expr != null && right.IsSideEffectFree) {
5407 await_expr.Statement.EmitPrologue (ec);
5408 left = await_expr.Statement.GetResultExpression (ec);
5412 await_expr = right as Await;
5413 if (await_expr != null && left.IsSideEffectFree) {
5414 await_expr.Statement.EmitPrologue (ec);
5415 right = await_expr.Statement.GetResultExpression (ec);
5420 return base.EmitToField (ec);
5423 protected override void CloneTo (CloneContext clonectx, Expression t)
5425 Binary target = (Binary) t;
5427 target.left = left.Clone (clonectx);
5428 target.right = right.Clone (clonectx);
5431 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5433 Arguments binder_args = new Arguments (4);
5435 MemberAccess sle = new MemberAccess (new MemberAccess (
5436 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5438 CSharpBinderFlags flags = 0;
5439 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5440 flags = CSharpBinderFlags.CheckedContext;
5442 if ((oper & Operator.LogicalMask) != 0)
5443 flags |= CSharpBinderFlags.BinaryOperationLogical;
5445 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5446 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5447 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5448 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5450 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5453 public override Expression CreateExpressionTree (ResolveContext ec)
5455 return CreateExpressionTree (ec, null);
5458 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5461 bool lift_arg = false;
5464 case Operator.Addition:
5465 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5466 method_name = "AddChecked";
5468 method_name = "Add";
5470 case Operator.BitwiseAnd:
5471 method_name = "And";
5473 case Operator.BitwiseOr:
5476 case Operator.Division:
5477 method_name = "Divide";
5479 case Operator.Equality:
5480 method_name = "Equal";
5483 case Operator.ExclusiveOr:
5484 method_name = "ExclusiveOr";
5486 case Operator.GreaterThan:
5487 method_name = "GreaterThan";
5490 case Operator.GreaterThanOrEqual:
5491 method_name = "GreaterThanOrEqual";
5494 case Operator.Inequality:
5495 method_name = "NotEqual";
5498 case Operator.LeftShift:
5499 method_name = "LeftShift";
5501 case Operator.LessThan:
5502 method_name = "LessThan";
5505 case Operator.LessThanOrEqual:
5506 method_name = "LessThanOrEqual";
5509 case Operator.LogicalAnd:
5510 method_name = "AndAlso";
5512 case Operator.LogicalOr:
5513 method_name = "OrElse";
5515 case Operator.Modulus:
5516 method_name = "Modulo";
5518 case Operator.Multiply:
5519 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5520 method_name = "MultiplyChecked";
5522 method_name = "Multiply";
5524 case Operator.RightShift:
5525 method_name = "RightShift";
5527 case Operator.Subtraction:
5528 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5529 method_name = "SubtractChecked";
5531 method_name = "Subtract";
5535 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5538 Arguments args = new Arguments (2);
5539 args.Add (new Argument (left.CreateExpressionTree (ec)));
5540 args.Add (new Argument (right.CreateExpressionTree (ec)));
5541 if (method != null) {
5543 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5545 args.Add (new Argument (method));
5548 return CreateExpressionFactoryCall (ec, method_name, args);
5551 public override object Accept (StructuralVisitor visitor)
5553 return visitor.Visit (this);
5559 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5560 // b, c, d... may be strings or objects.
5562 public class StringConcat : Expression
5564 Arguments arguments;
5566 StringConcat (Location loc)
5569 arguments = new Arguments (2);
5572 public override bool ContainsEmitWithAwait ()
5574 return arguments.ContainsEmitWithAwait ();
5577 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5579 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5580 throw new ArgumentException ();
5582 var s = new StringConcat (loc);
5583 s.type = rc.BuiltinTypes.String;
5584 s.eclass = ExprClass.Value;
5586 s.Append (rc, left);
5587 s.Append (rc, right);
5591 public override Expression CreateExpressionTree (ResolveContext ec)
5593 Argument arg = arguments [0];
5594 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5598 // Creates nested calls tree from an array of arguments used for IL emit
5600 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5602 Arguments concat_args = new Arguments (2);
5603 Arguments add_args = new Arguments (3);
5605 concat_args.Add (left);
5606 add_args.Add (new Argument (left_etree));
5608 concat_args.Add (arguments [pos]);
5609 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5611 var methods = GetConcatMethodCandidates ();
5612 if (methods == null)
5615 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5616 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5620 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5622 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5623 if (++pos == arguments.Count)
5626 left = new Argument (new EmptyExpression (method.ReturnType));
5627 return CreateExpressionAddCall (ec, left, expr, pos);
5630 protected override Expression DoResolve (ResolveContext ec)
5635 void Append (ResolveContext rc, Expression operand)
5640 StringConstant sc = operand as StringConstant;
5642 if (arguments.Count != 0) {
5643 Argument last_argument = arguments [arguments.Count - 1];
5644 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5645 if (last_expr_constant != null) {
5646 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5652 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5654 StringConcat concat_oper = operand as StringConcat;
5655 if (concat_oper != null) {
5656 arguments.AddRange (concat_oper.arguments);
5661 arguments.Add (new Argument (operand));
5664 IList<MemberSpec> GetConcatMethodCandidates ()
5666 return MemberCache.FindMembers (type, "Concat", true);
5669 public override void Emit (EmitContext ec)
5671 // Optimize by removing any extra null arguments, they are no-op
5672 for (int i = 0; i < arguments.Count; ++i) {
5673 if (arguments[i].Expr is NullConstant)
5674 arguments.RemoveAt (i--);
5677 var members = GetConcatMethodCandidates ();
5678 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5679 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5680 if (method != null) {
5681 var call = new CallEmitter ();
5682 call.EmitPredefined (ec, method, arguments, false);
5686 public override void FlowAnalysis (FlowAnalysisContext fc)
5688 arguments.FlowAnalysis (fc);
5691 public override SLE.Expression MakeExpression (BuilderContext ctx)
5693 if (arguments.Count != 2)
5694 throw new NotImplementedException ("arguments.Count != 2");
5696 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5697 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5702 // User-defined conditional logical operator
5704 public class ConditionalLogicalOperator : UserOperatorCall
5706 readonly bool is_and;
5707 Expression oper_expr;
5709 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5710 : base (oper, arguments, expr_tree, loc)
5712 this.is_and = is_and;
5713 eclass = ExprClass.Unresolved;
5716 protected override Expression DoResolve (ResolveContext ec)
5718 AParametersCollection pd = oper.Parameters;
5719 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5720 ec.Report.Error (217, loc,
5721 "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",
5722 oper.GetSignatureForError ());
5726 Expression left_dup = new EmptyExpression (type);
5727 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5728 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5729 if (op_true == null || op_false == null) {
5730 ec.Report.Error (218, loc,
5731 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5732 type.GetSignatureForError (), oper.GetSignatureForError ());
5736 oper_expr = is_and ? op_false : op_true;
5737 eclass = ExprClass.Value;
5741 public override void Emit (EmitContext ec)
5743 Label end_target = ec.DefineLabel ();
5746 // Emit and duplicate left argument
5748 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5749 if (right_contains_await) {
5750 arguments[0] = arguments[0].EmitToField (ec, false);
5751 arguments[0].Expr.Emit (ec);
5753 arguments[0].Expr.Emit (ec);
5754 ec.Emit (OpCodes.Dup);
5755 arguments.RemoveAt (0);
5758 oper_expr.EmitBranchable (ec, end_target, true);
5762 if (right_contains_await) {
5764 // Special handling when right expression contains await and left argument
5765 // could not be left on stack before logical branch
5767 Label skip_left_load = ec.DefineLabel ();
5768 ec.Emit (OpCodes.Br_S, skip_left_load);
5769 ec.MarkLabel (end_target);
5770 arguments[0].Expr.Emit (ec);
5771 ec.MarkLabel (skip_left_load);
5773 ec.MarkLabel (end_target);
5778 public class PointerArithmetic : Expression {
5779 Expression left, right;
5780 readonly Binary.Operator op;
5783 // We assume that `l' is always a pointer
5785 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5794 public override bool ContainsEmitWithAwait ()
5796 throw new NotImplementedException ();
5799 public override Expression CreateExpressionTree (ResolveContext ec)
5801 Error_PointerInsideExpressionTree (ec);
5805 protected override Expression DoResolve (ResolveContext ec)
5807 eclass = ExprClass.Variable;
5809 var pc = left.Type as PointerContainer;
5810 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5811 Error_VoidPointerOperation (ec);
5818 public override void Emit (EmitContext ec)
5820 TypeSpec op_type = left.Type;
5822 // It must be either array or fixed buffer
5824 if (TypeManager.HasElementType (op_type)) {
5825 element = TypeManager.GetElementType (op_type);
5827 FieldExpr fe = left as FieldExpr;
5829 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5834 int size = BuiltinTypeSpec.GetSize(element);
5835 TypeSpec rtype = right.Type;
5837 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5839 // handle (pointer - pointer)
5843 ec.Emit (OpCodes.Sub);
5847 ec.Emit (OpCodes.Sizeof, element);
5850 ec.Emit (OpCodes.Div);
5852 ec.Emit (OpCodes.Conv_I8);
5855 // handle + and - on (pointer op int)
5857 Constant left_const = left as Constant;
5858 if (left_const != null) {
5860 // Optimize ((T*)null) pointer operations
5862 if (left_const.IsDefaultValue) {
5863 left = EmptyExpression.Null;
5871 var right_const = right as Constant;
5872 if (right_const != null) {
5874 // Optimize 0-based arithmetic
5876 if (right_const.IsDefaultValue)
5880 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5882 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5884 // TODO: Should be the checks resolve context sensitive?
5885 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5886 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5892 switch (rtype.BuiltinType) {
5893 case BuiltinTypeSpec.Type.SByte:
5894 case BuiltinTypeSpec.Type.Byte:
5895 case BuiltinTypeSpec.Type.Short:
5896 case BuiltinTypeSpec.Type.UShort:
5897 ec.Emit (OpCodes.Conv_I);
5899 case BuiltinTypeSpec.Type.UInt:
5900 ec.Emit (OpCodes.Conv_U);
5904 if (right_const == null && size != 1){
5906 ec.Emit (OpCodes.Sizeof, element);
5909 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5910 ec.Emit (OpCodes.Conv_I8);
5912 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5915 if (left_const == null) {
5916 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5917 ec.Emit (OpCodes.Conv_I);
5918 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5919 ec.Emit (OpCodes.Conv_U);
5921 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5928 // A boolean-expression is an expression that yields a result
5931 public class BooleanExpression : ShimExpression
5933 public BooleanExpression (Expression expr)
5936 this.loc = expr.Location;
5939 public override Expression CreateExpressionTree (ResolveContext ec)
5941 // TODO: We should emit IsTrue (v4) instead of direct user operator
5942 // call but that would break csc compatibility
5943 return base.CreateExpressionTree (ec);
5946 protected override Expression DoResolve (ResolveContext ec)
5948 // A boolean-expression is required to be of a type
5949 // that can be implicitly converted to bool or of
5950 // a type that implements operator true
5952 expr = expr.Resolve (ec);
5956 Assign ass = expr as Assign;
5957 if (ass != null && ass.Source is Constant) {
5958 ec.Report.Warning (665, 3, loc,
5959 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5962 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5965 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5966 Arguments args = new Arguments (1);
5967 args.Add (new Argument (expr));
5968 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5971 type = ec.BuiltinTypes.Bool;
5972 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5973 if (converted != null)
5977 // If no implicit conversion to bool exists, try using `operator true'
5979 converted = GetOperatorTrue (ec, expr, loc);
5980 if (converted == null) {
5981 expr.Error_ValueCannotBeConverted (ec, type, false);
5988 public override object Accept (StructuralVisitor visitor)
5990 return visitor.Visit (this);
5994 public class BooleanExpressionFalse : Unary
5996 public BooleanExpressionFalse (Expression expr)
5997 : base (Operator.LogicalNot, expr, expr.Location)
6001 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6003 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6008 /// Implements the ternary conditional operator (?:)
6010 public class Conditional : Expression {
6011 Expression expr, true_expr, false_expr;
6013 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6016 this.true_expr = true_expr;
6017 this.false_expr = false_expr;
6023 public Expression Expr {
6029 public Expression TrueExpr {
6035 public Expression FalseExpr {
6043 public override bool ContainsEmitWithAwait ()
6045 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6048 public override Expression CreateExpressionTree (ResolveContext ec)
6050 Arguments args = new Arguments (3);
6051 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6052 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6053 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6054 return CreateExpressionFactoryCall (ec, "Condition", args);
6057 protected override Expression DoResolve (ResolveContext ec)
6059 expr = expr.Resolve (ec);
6060 true_expr = true_expr.Resolve (ec);
6061 false_expr = false_expr.Resolve (ec);
6063 if (true_expr == null || false_expr == null || expr == null)
6066 eclass = ExprClass.Value;
6067 TypeSpec true_type = true_expr.Type;
6068 TypeSpec false_type = false_expr.Type;
6072 // First, if an implicit conversion exists from true_expr
6073 // to false_expr, then the result type is of type false_expr.Type
6075 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6076 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6077 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6079 // Check if both can convert implicitly to each other's type
6083 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6084 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6086 // LAMESPEC: There seems to be hardcoded promotition to int type when
6087 // both sides are numeric constants and one side is int constant and
6088 // other side is numeric constant convertible to int.
6090 // var res = condition ? (short)1 : 1;
6092 // Type of res is int even if according to the spec the conversion is
6093 // ambiguous because 1 literal can be converted to short.
6095 if (conv_false_expr != null) {
6096 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6098 conv_false_expr = null;
6099 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6100 conv_false_expr = null;
6104 if (conv_false_expr != null) {
6105 ec.Report.Error (172, true_expr.Location,
6106 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6107 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6112 if (true_expr.Type != type)
6113 true_expr = EmptyCast.Create (true_expr, type);
6114 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6117 ec.Report.Error (173, true_expr.Location,
6118 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6119 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6124 Constant c = expr as Constant;
6126 bool is_false = c.IsDefaultValue;
6129 // Don't issue the warning for constant expressions
6131 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6132 // CSC: Missing warning
6133 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6136 return ReducedExpression.Create (
6137 is_false ? false_expr : true_expr, this,
6138 false_expr is Constant && true_expr is Constant).Resolve (ec);
6144 public override void Emit (EmitContext ec)
6146 Label false_target = ec.DefineLabel ();
6147 Label end_target = ec.DefineLabel ();
6149 expr.EmitBranchable (ec, false_target, false);
6150 true_expr.Emit (ec);
6153 // Verifier doesn't support interface merging. When there are two types on
6154 // the stack without common type hint and the common type is an interface.
6155 // Use temporary local to give verifier hint on what type to unify the stack
6157 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6158 var temp = ec.GetTemporaryLocal (type);
6159 ec.Emit (OpCodes.Stloc, temp);
6160 ec.Emit (OpCodes.Ldloc, temp);
6161 ec.FreeTemporaryLocal (temp, type);
6164 ec.Emit (OpCodes.Br, end_target);
6165 ec.MarkLabel (false_target);
6166 false_expr.Emit (ec);
6167 ec.MarkLabel (end_target);
6170 public override void FlowAnalysis (FlowAnalysisContext fc)
6172 expr.FlowAnalysisConditional (fc);
6173 var expr_true = fc.DefiniteAssignmentOnTrue;
6174 var expr_false = fc.DefiniteAssignmentOnFalse;
6176 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6177 true_expr.FlowAnalysis (fc);
6178 var true_fc = fc.DefiniteAssignment;
6180 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6181 false_expr.FlowAnalysis (fc);
6183 fc.DefiniteAssignment &= true_fc;
6186 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6188 expr.FlowAnalysisConditional (fc);
6189 var expr_true = fc.DefiniteAssignmentOnTrue;
6190 var expr_false = fc.DefiniteAssignmentOnFalse;
6192 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6193 true_expr.FlowAnalysisConditional (fc);
6194 var true_fc = fc.DefiniteAssignment;
6195 var true_da_true = fc.DefiniteAssignmentOnTrue;
6196 var true_da_false = fc.DefiniteAssignmentOnFalse;
6198 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6199 false_expr.FlowAnalysisConditional (fc);
6201 fc.DefiniteAssignment &= true_fc;
6202 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6203 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6206 protected override void CloneTo (CloneContext clonectx, Expression t)
6208 Conditional target = (Conditional) t;
6210 target.expr = expr.Clone (clonectx);
6211 target.true_expr = true_expr.Clone (clonectx);
6212 target.false_expr = false_expr.Clone (clonectx);
6216 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6218 LocalTemporary temp;
6221 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6222 public abstract void SetHasAddressTaken ();
6224 public abstract bool IsLockedByStatement { get; set; }
6226 public abstract bool IsFixed { get; }
6227 public abstract bool IsRef { get; }
6228 public abstract string Name { get; }
6231 // Variable IL data, it has to be protected to encapsulate hoisted variables
6233 protected abstract ILocalVariable Variable { get; }
6236 // Variable flow-analysis data
6238 public abstract VariableInfo VariableInfo { get; }
6241 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6243 HoistedVariable hv = GetHoistedVariable (ec);
6245 hv.AddressOf (ec, mode);
6249 Variable.EmitAddressOf (ec);
6252 public override bool ContainsEmitWithAwait ()
6257 public override Expression CreateExpressionTree (ResolveContext ec)
6259 HoistedVariable hv = GetHoistedVariable (ec);
6261 return hv.CreateExpressionTree ();
6263 Arguments arg = new Arguments (1);
6264 arg.Add (new Argument (this));
6265 return CreateExpressionFactoryCall (ec, "Constant", arg);
6268 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6270 if (IsLockedByStatement) {
6271 rc.Report.Warning (728, 2, loc,
6272 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6279 public override void Emit (EmitContext ec)
6284 public override void EmitSideEffect (EmitContext ec)
6290 // This method is used by parameters that are references, that are
6291 // being passed as references: we only want to pass the pointer (that
6292 // is already stored in the parameter, not the address of the pointer,
6293 // and not the value of the variable).
6295 public void EmitLoad (EmitContext ec)
6300 public void Emit (EmitContext ec, bool leave_copy)
6302 HoistedVariable hv = GetHoistedVariable (ec);
6304 hv.Emit (ec, leave_copy);
6312 // If we are a reference, we loaded on the stack a pointer
6313 // Now lets load the real value
6315 ec.EmitLoadFromPtr (type);
6319 ec.Emit (OpCodes.Dup);
6322 temp = new LocalTemporary (Type);
6328 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6329 bool prepare_for_load)
6331 HoistedVariable hv = GetHoistedVariable (ec);
6333 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6337 New n_source = source as New;
6338 if (n_source != null) {
6339 if (!n_source.Emit (ec, this)) {
6343 ec.EmitLoadFromPtr (type);
6355 ec.Emit (OpCodes.Dup);
6357 temp = new LocalTemporary (Type);
6363 ec.EmitStoreFromPtr (type);
6365 Variable.EmitAssign (ec);
6373 public override Expression EmitToField (EmitContext ec)
6375 HoistedVariable hv = GetHoistedVariable (ec);
6377 return hv.EmitToField (ec);
6380 return base.EmitToField (ec);
6383 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6385 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6388 public HoistedVariable GetHoistedVariable (EmitContext ec)
6390 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6393 public override string GetSignatureForError ()
6398 public bool IsHoisted {
6399 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6404 // Resolved reference to a local variable
6406 public class LocalVariableReference : VariableReference
6408 public LocalVariable local_info;
6410 public LocalVariableReference (LocalVariable li, Location l)
6412 this.local_info = li;
6416 public override VariableInfo VariableInfo {
6417 get { return local_info.VariableInfo; }
6420 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6422 return local_info.HoistedVariant;
6428 // A local variable is always fixed
6430 public override bool IsFixed {
6436 public override bool IsLockedByStatement {
6438 return local_info.IsLocked;
6441 local_info.IsLocked = value;
6445 public override bool IsRef {
6446 get { return false; }
6449 public override string Name {
6450 get { return local_info.Name; }
6455 public override void FlowAnalysis (FlowAnalysisContext fc)
6457 VariableInfo variable_info = VariableInfo;
6458 if (variable_info == null)
6461 if (fc.IsDefinitelyAssigned (variable_info))
6464 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6465 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6468 public override void SetHasAddressTaken ()
6470 local_info.SetHasAddressTaken ();
6473 void DoResolveBase (ResolveContext ec)
6476 // If we are referencing a variable from the external block
6477 // flag it for capturing
6479 if (ec.MustCaptureVariable (local_info)) {
6480 if (local_info.AddressTaken) {
6481 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6482 } else if (local_info.IsFixed) {
6483 ec.Report.Error (1764, loc,
6484 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6485 GetSignatureForError ());
6488 if (ec.IsVariableCapturingRequired) {
6489 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6490 storey.CaptureLocalVariable (ec, local_info);
6494 eclass = ExprClass.Variable;
6495 type = local_info.Type;
6498 protected override Expression DoResolve (ResolveContext ec)
6500 local_info.SetIsUsed ();
6506 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6509 // Don't be too pedantic when variable is used as out param or for some broken code
6510 // which uses property/indexer access to run some initialization
6512 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6513 local_info.SetIsUsed ();
6515 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6516 if (rhs == EmptyExpression.LValueMemberAccess) {
6517 // CS1654 already reported
6521 if (rhs == EmptyExpression.OutAccess) {
6522 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6523 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6524 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6525 } else if (rhs == EmptyExpression.UnaryAddress) {
6526 code = 459; msg = "Cannot take the address of {1} `{0}'";
6528 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6530 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6534 if (eclass == ExprClass.Unresolved)
6537 return base.DoResolveLValue (ec, rhs);
6540 public override int GetHashCode ()
6542 return local_info.GetHashCode ();
6545 public override bool Equals (object obj)
6547 LocalVariableReference lvr = obj as LocalVariableReference;
6551 return local_info == lvr.local_info;
6554 protected override ILocalVariable Variable {
6555 get { return local_info; }
6558 public override string ToString ()
6560 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6563 protected override void CloneTo (CloneContext clonectx, Expression t)
6570 /// This represents a reference to a parameter in the intermediate
6573 public class ParameterReference : VariableReference
6575 protected ParametersBlock.ParameterInfo pi;
6577 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6585 public override bool IsLockedByStatement {
6590 pi.IsLocked = value;
6594 public override bool IsRef {
6595 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6598 bool HasOutModifier {
6599 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6602 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6604 return pi.Parameter.HoistedVariant;
6608 // A ref or out parameter is classified as a moveable variable, even
6609 // if the argument given for the parameter is a fixed variable
6611 public override bool IsFixed {
6612 get { return !IsRef; }
6615 public override string Name {
6616 get { return Parameter.Name; }
6619 public Parameter Parameter {
6620 get { return pi.Parameter; }
6623 public override VariableInfo VariableInfo {
6624 get { return pi.VariableInfo; }
6627 protected override ILocalVariable Variable {
6628 get { return Parameter; }
6633 public override void AddressOf (EmitContext ec, AddressOp mode)
6636 // ParameterReferences might already be a reference
6643 base.AddressOf (ec, mode);
6646 public override void SetHasAddressTaken ()
6648 Parameter.HasAddressTaken = true;
6651 bool DoResolveBase (ResolveContext ec)
6653 if (eclass != ExprClass.Unresolved)
6656 type = pi.ParameterType;
6657 eclass = ExprClass.Variable;
6660 // If we are referencing a parameter from the external block
6661 // flag it for capturing
6663 if (ec.MustCaptureVariable (pi)) {
6664 if (Parameter.HasAddressTaken)
6665 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6668 ec.Report.Error (1628, loc,
6669 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6670 Name, ec.CurrentAnonymousMethod.ContainerType);
6673 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6674 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6675 storey.CaptureParameter (ec, pi, this);
6682 public override int GetHashCode ()
6684 return Name.GetHashCode ();
6687 public override bool Equals (object obj)
6689 ParameterReference pr = obj as ParameterReference;
6693 return Name == pr.Name;
6696 protected override void CloneTo (CloneContext clonectx, Expression target)
6702 public override Expression CreateExpressionTree (ResolveContext ec)
6704 HoistedVariable hv = GetHoistedVariable (ec);
6706 return hv.CreateExpressionTree ();
6708 return Parameter.ExpressionTreeVariableReference ();
6711 protected override Expression DoResolve (ResolveContext ec)
6713 if (!DoResolveBase (ec))
6719 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6721 if (!DoResolveBase (ec))
6724 if (Parameter.HoistedVariant != null)
6725 Parameter.HoistedVariant.IsAssigned = true;
6727 return base.DoResolveLValue (ec, right_side);
6730 public override void FlowAnalysis (FlowAnalysisContext fc)
6732 VariableInfo variable_info = VariableInfo;
6733 if (variable_info == null)
6736 if (fc.IsDefinitelyAssigned (variable_info))
6739 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6740 fc.SetVariableAssigned (variable_info);
6745 /// Invocation of methods or delegates.
6747 public class Invocation : ExpressionStatement
6749 public class Predefined : Invocation
6751 public Predefined (MethodGroupExpr expr, Arguments arguments)
6752 : base (expr, arguments)
6757 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6759 if (!rc.IsObsolete) {
6760 var member = mg.BestCandidate;
6761 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6763 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6770 protected Arguments arguments;
6771 protected Expression expr;
6772 protected MethodGroupExpr mg;
6773 bool conditional_access_receiver;
6775 public Invocation (Expression expr, Arguments arguments)
6778 this.arguments = arguments;
6780 loc = expr.Location;
6785 public Arguments Arguments {
6791 public Expression Exp {
6797 public MethodGroupExpr MethodGroup {
6803 public override Location StartLocation {
6805 return expr.StartLocation;
6811 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6813 if (MethodGroup == null)
6816 var candidate = MethodGroup.BestCandidate;
6817 if (candidate == null || !(candidate.IsStatic || Exp is This))
6820 var args_count = arguments == null ? 0 : arguments.Count;
6821 if (args_count != body.Parameters.Count)
6824 var lambda_parameters = body.Block.Parameters.FixedParameters;
6825 for (int i = 0; i < args_count; ++i) {
6826 var pr = arguments[i].Expr as ParameterReference;
6830 if (lambda_parameters[i] != pr.Parameter)
6833 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6837 var emg = MethodGroup as ExtensionMethodGroupExpr;
6839 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6840 if (candidate.IsGeneric) {
6841 var targs = new TypeExpression [candidate.Arity];
6842 for (int i = 0; i < targs.Length; ++i) {
6843 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6846 mg.SetTypeArguments (null, new TypeArguments (targs));
6855 protected override void CloneTo (CloneContext clonectx, Expression t)
6857 Invocation target = (Invocation) t;
6859 if (arguments != null)
6860 target.arguments = arguments.Clone (clonectx);
6862 target.expr = expr.Clone (clonectx);
6865 public override bool ContainsEmitWithAwait ()
6867 if (arguments != null && arguments.ContainsEmitWithAwait ())
6870 return mg.ContainsEmitWithAwait ();
6873 public override Expression CreateExpressionTree (ResolveContext ec)
6875 Expression instance = mg.IsInstance ?
6876 mg.InstanceExpression.CreateExpressionTree (ec) :
6877 new NullLiteral (loc);
6879 var args = Arguments.CreateForExpressionTree (ec, arguments,
6881 mg.CreateExpressionTree (ec));
6883 return CreateExpressionFactoryCall (ec, "Call", args);
6886 protected override Expression DoResolve (ResolveContext rc)
6888 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
6889 if (expr.HasConditionalAccess ()) {
6890 conditional_access_receiver = true;
6891 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
6892 return DoResolveInvocation (rc);
6897 return DoResolveInvocation (rc);
6900 Expression DoResolveInvocation (ResolveContext ec)
6902 Expression member_expr;
6903 var atn = expr as ATypeNameExpression;
6905 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6906 if (member_expr != null) {
6907 var name_of = member_expr as NameOf;
6908 if (name_of != null) {
6909 return name_of.ResolveOverload (ec, arguments);
6912 member_expr = member_expr.Resolve (ec);
6915 member_expr = expr.Resolve (ec);
6918 if (member_expr == null)
6922 // Next, evaluate all the expressions in the argument list
6924 bool dynamic_arg = false;
6925 if (arguments != null)
6926 arguments.Resolve (ec, out dynamic_arg);
6928 TypeSpec expr_type = member_expr.Type;
6929 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6930 return DoResolveDynamic (ec, member_expr);
6932 mg = member_expr as MethodGroupExpr;
6933 Expression invoke = null;
6936 if (expr_type != null && expr_type.IsDelegate) {
6937 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
6938 invoke = invoke.Resolve (ec);
6939 if (invoke == null || !dynamic_arg)
6942 if (member_expr is RuntimeValueExpression) {
6943 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6944 member_expr.Type.GetSignatureForError ());
6948 MemberExpr me = member_expr as MemberExpr;
6950 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6954 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6955 member_expr.GetSignatureForError ());
6960 if (invoke == null) {
6961 mg = DoResolveOverload (ec);
6967 return DoResolveDynamic (ec, member_expr);
6969 var method = mg.BestCandidate;
6970 type = mg.BestCandidateReturnType;
6971 if (conditional_access_receiver)
6972 type = LiftMemberType (ec, type);
6974 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6976 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6978 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6982 IsSpecialMethodInvocation (ec, method, loc);
6984 eclass = ExprClass.Value;
6988 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6991 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6993 args = dmb.Arguments;
6994 if (arguments != null)
6995 args.AddRange (arguments);
6996 } else if (mg == null) {
6997 if (arguments == null)
6998 args = new Arguments (1);
7002 args.Insert (0, new Argument (memberExpr));
7006 ec.Report.Error (1971, loc,
7007 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7012 if (arguments == null)
7013 args = new Arguments (1);
7017 MemberAccess ma = expr as MemberAccess;
7019 var inst = mg.InstanceExpression;
7020 var left_type = inst as TypeExpr;
7021 if (left_type != null) {
7022 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7023 } else if (inst != null) {
7025 // Any value type has to be pass as by-ref to get back the same
7026 // instance on which the member was called
7028 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7029 Argument.AType.Ref : Argument.AType.None;
7030 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7032 } else { // is SimpleName
7034 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7036 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7041 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7044 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7046 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7049 public override void FlowAnalysis (FlowAnalysisContext fc)
7051 if (mg.IsConditionallyExcluded)
7054 mg.FlowAnalysis (fc);
7056 if (arguments != null)
7057 arguments.FlowAnalysis (fc);
7059 if (conditional_access_receiver)
7060 fc.ConditionalAccessEnd ();
7063 public override string GetSignatureForError ()
7065 return mg.GetSignatureForError ();
7068 public override bool HasConditionalAccess ()
7070 return expr.HasConditionalAccess ();
7074 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7075 // or the type dynamic, then the member is invocable
7077 public static bool IsMemberInvocable (MemberSpec member)
7079 switch (member.Kind) {
7080 case MemberKind.Event:
7082 case MemberKind.Field:
7083 case MemberKind.Property:
7084 var m = member as IInterfaceMemberSpec;
7085 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7091 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7093 if (!method.IsReservedMethod)
7096 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7099 ec.Report.SymbolRelatedToPreviousError (method);
7100 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7101 method.GetSignatureForError ());
7106 public override void Emit (EmitContext ec)
7108 if (mg.IsConditionallyExcluded)
7111 if (conditional_access_receiver)
7112 mg.EmitCall (ec, arguments, type, false);
7114 mg.EmitCall (ec, arguments, false);
7117 public override void EmitStatement (EmitContext ec)
7119 if (mg.IsConditionallyExcluded)
7122 if (conditional_access_receiver)
7123 mg.EmitCall (ec, arguments, type, true);
7125 mg.EmitCall (ec, arguments, true);
7128 public override SLE.Expression MakeExpression (BuilderContext ctx)
7130 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7133 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7136 throw new NotSupportedException ();
7138 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7139 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7143 public override object Accept (StructuralVisitor visitor)
7145 return visitor.Visit (this);
7150 // Implements simple new expression
7152 public class New : ExpressionStatement, IMemoryLocation
7154 protected Arguments arguments;
7157 // During bootstrap, it contains the RequestedType,
7158 // but if `type' is not null, it *might* contain a NewDelegate
7159 // (because of field multi-initialization)
7161 protected Expression RequestedType;
7163 protected MethodSpec method;
7165 public New (Expression requested_type, Arguments arguments, Location l)
7167 RequestedType = requested_type;
7168 this.arguments = arguments;
7173 public Arguments Arguments {
7180 // Returns true for resolved `new S()'
7182 public bool IsDefaultStruct {
7184 return arguments == null && type.IsStruct && GetType () == typeof (New);
7188 public Expression TypeExpression {
7190 return RequestedType;
7197 /// Converts complex core type syntax like 'new int ()' to simple constant
7199 public static Constant Constantify (TypeSpec t, Location loc)
7201 switch (t.BuiltinType) {
7202 case BuiltinTypeSpec.Type.Int:
7203 return new IntConstant (t, 0, loc);
7204 case BuiltinTypeSpec.Type.UInt:
7205 return new UIntConstant (t, 0, loc);
7206 case BuiltinTypeSpec.Type.Long:
7207 return new LongConstant (t, 0, loc);
7208 case BuiltinTypeSpec.Type.ULong:
7209 return new ULongConstant (t, 0, loc);
7210 case BuiltinTypeSpec.Type.Float:
7211 return new FloatConstant (t, 0, loc);
7212 case BuiltinTypeSpec.Type.Double:
7213 return new DoubleConstant (t, 0, loc);
7214 case BuiltinTypeSpec.Type.Short:
7215 return new ShortConstant (t, 0, loc);
7216 case BuiltinTypeSpec.Type.UShort:
7217 return new UShortConstant (t, 0, loc);
7218 case BuiltinTypeSpec.Type.SByte:
7219 return new SByteConstant (t, 0, loc);
7220 case BuiltinTypeSpec.Type.Byte:
7221 return new ByteConstant (t, 0, loc);
7222 case BuiltinTypeSpec.Type.Char:
7223 return new CharConstant (t, '\0', loc);
7224 case BuiltinTypeSpec.Type.Bool:
7225 return new BoolConstant (t, false, loc);
7226 case BuiltinTypeSpec.Type.Decimal:
7227 return new DecimalConstant (t, 0, loc);
7231 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7233 if (t.IsNullableType)
7234 return Nullable.LiftedNull.Create (t, loc);
7239 public override bool ContainsEmitWithAwait ()
7241 return arguments != null && arguments.ContainsEmitWithAwait ();
7245 // Checks whether the type is an interface that has the
7246 // [ComImport, CoClass] attributes and must be treated
7249 public Expression CheckComImport (ResolveContext ec)
7251 if (!type.IsInterface)
7255 // Turn the call into:
7256 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7258 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7259 if (real_class == null)
7262 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7263 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7264 return cast.Resolve (ec);
7267 public override Expression CreateExpressionTree (ResolveContext ec)
7270 if (method == null) {
7271 args = new Arguments (1);
7272 args.Add (new Argument (new TypeOf (type, loc)));
7274 args = Arguments.CreateForExpressionTree (ec,
7275 arguments, new TypeOfMethod (method, loc));
7278 return CreateExpressionFactoryCall (ec, "New", args);
7281 protected override Expression DoResolve (ResolveContext ec)
7283 type = RequestedType.ResolveAsType (ec);
7287 eclass = ExprClass.Value;
7289 if (type.IsPointer) {
7290 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7291 type.GetSignatureForError ());
7295 if (arguments == null) {
7296 Constant c = Constantify (type, RequestedType.Location);
7298 return ReducedExpression.Create (c, this);
7301 if (type.IsDelegate) {
7302 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7305 var tparam = type as TypeParameterSpec;
7306 if (tparam != null) {
7308 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7309 // where type parameter constraint is inflated to struct
7311 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7312 ec.Report.Error (304, loc,
7313 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7314 type.GetSignatureForError ());
7317 if ((arguments != null) && (arguments.Count != 0)) {
7318 ec.Report.Error (417, loc,
7319 "`{0}': cannot provide arguments when creating an instance of a variable type",
7320 type.GetSignatureForError ());
7326 if (type.IsStatic) {
7327 ec.Report.SymbolRelatedToPreviousError (type);
7328 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7332 if (type.IsInterface || type.IsAbstract){
7333 if (!TypeManager.IsGenericType (type)) {
7334 RequestedType = CheckComImport (ec);
7335 if (RequestedType != null)
7336 return RequestedType;
7339 ec.Report.SymbolRelatedToPreviousError (type);
7340 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7345 if (arguments != null) {
7346 arguments.Resolve (ec, out dynamic);
7351 method = ConstructorLookup (ec, type, ref arguments, loc);
7354 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7355 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7361 void DoEmitTypeParameter (EmitContext ec)
7363 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7367 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7368 ec.Emit (OpCodes.Call, ctor_factory);
7372 // This Emit can be invoked in two contexts:
7373 // * As a mechanism that will leave a value on the stack (new object)
7374 // * As one that wont (init struct)
7376 // If we are dealing with a ValueType, we have a few
7377 // situations to deal with:
7379 // * The target is a ValueType, and we have been provided
7380 // the instance (this is easy, we are being assigned).
7382 // * The target of New is being passed as an argument,
7383 // to a boxing operation or a function that takes a
7386 // In this case, we need to create a temporary variable
7387 // that is the argument of New.
7389 // Returns whether a value is left on the stack
7391 // *** Implementation note ***
7393 // To benefit from this optimization, each assignable expression
7394 // has to manually cast to New and call this Emit.
7396 // TODO: It's worth to implement it for arrays and fields
7398 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7400 bool is_value_type = type.IsStructOrEnum;
7401 VariableReference vr = target as VariableReference;
7403 if (target != null && is_value_type && (vr != null || method == null)) {
7404 target.AddressOf (ec, AddressOp.Store);
7405 } else if (vr != null && vr.IsRef) {
7409 if (arguments != null) {
7410 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7411 arguments = arguments.Emit (ec, false, true);
7413 arguments.Emit (ec);
7416 if (is_value_type) {
7417 if (method == null) {
7418 ec.Emit (OpCodes.Initobj, type);
7423 ec.MarkCallEntry (loc);
7424 ec.Emit (OpCodes.Call, method);
7429 if (type is TypeParameterSpec) {
7430 DoEmitTypeParameter (ec);
7434 ec.MarkCallEntry (loc);
7435 ec.Emit (OpCodes.Newobj, method);
7439 public override void Emit (EmitContext ec)
7441 LocalTemporary v = null;
7442 if (method == null && type.IsStructOrEnum) {
7443 // TODO: Use temporary variable from pool
7444 v = new LocalTemporary (type);
7451 public override void EmitStatement (EmitContext ec)
7453 LocalTemporary v = null;
7454 if (method == null && TypeSpec.IsValueType (type)) {
7455 // TODO: Use temporary variable from pool
7456 v = new LocalTemporary (type);
7460 ec.Emit (OpCodes.Pop);
7463 public override void FlowAnalysis (FlowAnalysisContext fc)
7465 if (arguments != null)
7466 arguments.FlowAnalysis (fc);
7469 public void AddressOf (EmitContext ec, AddressOp mode)
7471 EmitAddressOf (ec, mode);
7474 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7476 LocalTemporary value_target = new LocalTemporary (type);
7478 if (type is TypeParameterSpec) {
7479 DoEmitTypeParameter (ec);
7480 value_target.Store (ec);
7481 value_target.AddressOf (ec, mode);
7482 return value_target;
7485 value_target.AddressOf (ec, AddressOp.Store);
7487 if (method == null) {
7488 ec.Emit (OpCodes.Initobj, type);
7490 if (arguments != null)
7491 arguments.Emit (ec);
7493 ec.Emit (OpCodes.Call, method);
7496 value_target.AddressOf (ec, mode);
7497 return value_target;
7500 protected override void CloneTo (CloneContext clonectx, Expression t)
7502 New target = (New) t;
7504 target.RequestedType = RequestedType.Clone (clonectx);
7505 if (arguments != null){
7506 target.arguments = arguments.Clone (clonectx);
7510 public override SLE.Expression MakeExpression (BuilderContext ctx)
7513 return base.MakeExpression (ctx);
7515 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7519 public override object Accept (StructuralVisitor visitor)
7521 return visitor.Visit (this);
7526 // Array initializer expression, the expression is allowed in
7527 // variable or field initialization only which makes it tricky as
7528 // the type has to be infered based on the context either from field
7529 // type or variable type (think of multiple declarators)
7531 public class ArrayInitializer : Expression
7533 List<Expression> elements;
7534 BlockVariable variable;
7536 public ArrayInitializer (List<Expression> init, Location loc)
7542 public ArrayInitializer (int count, Location loc)
7543 : this (new List<Expression> (count), loc)
7547 public ArrayInitializer (Location loc)
7555 get { return elements.Count; }
7558 public List<Expression> Elements {
7564 public Expression this [int index] {
7566 return elements [index];
7570 public BlockVariable VariableDeclaration {
7581 public void Add (Expression expr)
7583 elements.Add (expr);
7586 public override bool ContainsEmitWithAwait ()
7588 throw new NotSupportedException ();
7591 public override Expression CreateExpressionTree (ResolveContext ec)
7593 throw new NotSupportedException ("ET");
7596 protected override void CloneTo (CloneContext clonectx, Expression t)
7598 var target = (ArrayInitializer) t;
7600 target.elements = new List<Expression> (elements.Count);
7601 foreach (var element in elements)
7602 target.elements.Add (element.Clone (clonectx));
7605 protected override Expression DoResolve (ResolveContext rc)
7607 var current_field = rc.CurrentMemberDefinition as FieldBase;
7608 TypeExpression type;
7609 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7610 type = new TypeExpression (current_field.MemberType, current_field.Location);
7611 } else if (variable != null) {
7612 if (variable.TypeExpression is VarExpr) {
7613 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7614 return EmptyExpression.Null;
7617 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7619 throw new NotImplementedException ("Unexpected array initializer context");
7622 return new ArrayCreation (type, this).Resolve (rc);
7625 public override void Emit (EmitContext ec)
7627 throw new InternalErrorException ("Missing Resolve call");
7630 public override void FlowAnalysis (FlowAnalysisContext fc)
7632 throw new InternalErrorException ("Missing Resolve call");
7635 public override object Accept (StructuralVisitor visitor)
7637 return visitor.Visit (this);
7642 /// 14.5.10.2: Represents an array creation expression.
7646 /// There are two possible scenarios here: one is an array creation
7647 /// expression that specifies the dimensions and optionally the
7648 /// initialization data and the other which does not need dimensions
7649 /// specified but where initialization data is mandatory.
7651 public class ArrayCreation : Expression
7653 FullNamedExpression requested_base_type;
7654 ArrayInitializer initializers;
7657 // The list of Argument types.
7658 // This is used to construct the `newarray' or constructor signature
7660 protected List<Expression> arguments;
7662 protected TypeSpec array_element_type;
7664 protected int dimensions;
7665 protected readonly ComposedTypeSpecifier rank;
7666 Expression first_emit;
7667 LocalTemporary first_emit_temp;
7669 protected List<Expression> array_data;
7671 Dictionary<int, int> bounds;
7674 // The number of constants in array initializers
7675 int const_initializers_count;
7676 bool only_constant_initializers;
7678 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7679 : this (requested_base_type, rank, initializers, l)
7681 arguments = new List<Expression> (exprs);
7682 num_arguments = arguments.Count;
7686 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7688 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7690 this.requested_base_type = requested_base_type;
7692 this.initializers = initializers;
7696 num_arguments = rank.Dimension;
7700 // For compiler generated single dimensional arrays only
7702 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7703 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7708 // For expressions like int[] foo = { 1, 2, 3 };
7710 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7711 : this (requested_base_type, null, initializers, initializers.Location)
7715 public ComposedTypeSpecifier Rank {
7721 public FullNamedExpression TypeExpression {
7723 return this.requested_base_type;
7727 public ArrayInitializer Initializers {
7729 return this.initializers;
7733 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7735 if (initializers != null && bounds == null) {
7737 // We use this to store all the data values in the order in which we
7738 // will need to store them in the byte blob later
7740 array_data = new List<Expression> (probe.Count);
7741 bounds = new Dictionary<int, int> ();
7744 if (specified_dims) {
7745 Expression a = arguments [idx];
7750 a = ConvertExpressionToArrayIndex (ec, a);
7756 if (initializers != null) {
7757 Constant c = a as Constant;
7758 if (c == null && a is ArrayIndexCast)
7759 c = ((ArrayIndexCast) a).Child as Constant;
7762 ec.Report.Error (150, a.Location, "A constant value is expected");
7768 value = System.Convert.ToInt32 (c.GetValue ());
7770 ec.Report.Error (150, a.Location, "A constant value is expected");
7774 // TODO: probe.Count does not fit ulong in
7775 if (value != probe.Count) {
7776 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7780 bounds[idx] = value;
7784 if (initializers == null)
7787 for (int i = 0; i < probe.Count; ++i) {
7789 if (o is ArrayInitializer) {
7790 var sub_probe = o as ArrayInitializer;
7791 if (idx + 1 >= dimensions){
7792 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7796 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7797 if (!bounds.ContainsKey(idx + 1))
7798 bounds[idx + 1] = sub_probe.Count;
7800 if (bounds[idx + 1] != sub_probe.Count) {
7801 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7805 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7808 } else if (child_bounds > 1) {
7809 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7811 Expression element = ResolveArrayElement (ec, o);
7812 if (element == null)
7815 // Initializers with the default values can be ignored
7816 Constant c = element as Constant;
7818 if (!c.IsDefaultInitializer (array_element_type)) {
7819 ++const_initializers_count;
7822 only_constant_initializers = false;
7825 array_data.Add (element);
7832 public override bool ContainsEmitWithAwait ()
7834 foreach (var arg in arguments) {
7835 if (arg.ContainsEmitWithAwait ())
7839 return InitializersContainAwait ();
7842 public override Expression CreateExpressionTree (ResolveContext ec)
7846 if (array_data == null) {
7847 args = new Arguments (arguments.Count + 1);
7848 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7849 foreach (Expression a in arguments)
7850 args.Add (new Argument (a.CreateExpressionTree (ec)));
7852 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7855 if (dimensions > 1) {
7856 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7860 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7861 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7862 if (array_data != null) {
7863 for (int i = 0; i < array_data.Count; ++i) {
7864 Expression e = array_data [i];
7865 args.Add (new Argument (e.CreateExpressionTree (ec)));
7869 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7872 void UpdateIndices (ResolveContext rc)
7875 for (var probe = initializers; probe != null;) {
7876 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7878 bounds[i++] = probe.Count;
7880 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7881 probe = (ArrayInitializer) probe[0];
7882 } else if (dimensions > i) {
7890 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7892 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7895 public override void FlowAnalysis (FlowAnalysisContext fc)
7897 foreach (var arg in arguments)
7898 arg.FlowAnalysis (fc);
7900 if (array_data != null) {
7901 foreach (var ad in array_data)
7902 ad.FlowAnalysis (fc);
7906 bool InitializersContainAwait ()
7908 if (array_data == null)
7911 foreach (var expr in array_data) {
7912 if (expr.ContainsEmitWithAwait ())
7919 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7921 element = element.Resolve (ec);
7922 if (element == null)
7925 if (element is CompoundAssign.TargetExpression) {
7926 if (first_emit != null)
7927 throw new InternalErrorException ("Can only handle one mutator at a time");
7928 first_emit = element;
7929 element = first_emit_temp = new LocalTemporary (element.Type);
7932 return Convert.ImplicitConversionRequired (
7933 ec, element, array_element_type, loc);
7936 protected bool ResolveInitializers (ResolveContext ec)
7939 only_constant_initializers = true;
7942 if (arguments != null) {
7944 for (int i = 0; i < arguments.Count; ++i) {
7945 res &= CheckIndices (ec, initializers, i, true, dimensions);
7946 if (initializers != null)
7953 arguments = new List<Expression> ();
7955 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7964 // Resolved the type of the array
7966 bool ResolveArrayType (ResolveContext ec)
7971 FullNamedExpression array_type_expr;
7972 if (num_arguments > 0) {
7973 array_type_expr = new ComposedCast (requested_base_type, rank);
7975 array_type_expr = requested_base_type;
7978 type = array_type_expr.ResolveAsType (ec);
7979 if (array_type_expr == null)
7982 var ac = type as ArrayContainer;
7984 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7988 array_element_type = ac.Element;
7989 dimensions = ac.Rank;
7994 protected override Expression DoResolve (ResolveContext ec)
7999 if (!ResolveArrayType (ec))
8003 // validate the initializers and fill in any missing bits
8005 if (!ResolveInitializers (ec))
8008 eclass = ExprClass.Value;
8012 byte [] MakeByteBlob ()
8017 int count = array_data.Count;
8019 TypeSpec element_type = array_element_type;
8020 if (element_type.IsEnum)
8021 element_type = EnumSpec.GetUnderlyingType (element_type);
8023 factor = BuiltinTypeSpec.GetSize (element_type);
8025 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8027 data = new byte [(count * factor + 3) & ~3];
8030 for (int i = 0; i < count; ++i) {
8031 var c = array_data[i] as Constant;
8037 object v = c.GetValue ();
8039 switch (element_type.BuiltinType) {
8040 case BuiltinTypeSpec.Type.Long:
8041 long lval = (long) v;
8043 for (int j = 0; j < factor; ++j) {
8044 data[idx + j] = (byte) (lval & 0xFF);
8048 case BuiltinTypeSpec.Type.ULong:
8049 ulong ulval = (ulong) v;
8051 for (int j = 0; j < factor; ++j) {
8052 data[idx + j] = (byte) (ulval & 0xFF);
8053 ulval = (ulval >> 8);
8056 case BuiltinTypeSpec.Type.Float:
8057 var fval = SingleConverter.SingleToInt32Bits((float) v);
8059 data[idx] = (byte) (fval & 0xff);
8060 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8061 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8062 data[idx + 3] = (byte) (fval >> 24);
8064 case BuiltinTypeSpec.Type.Double:
8065 element = BitConverter.GetBytes ((double) v);
8067 for (int j = 0; j < factor; ++j)
8068 data[idx + j] = element[j];
8070 // FIXME: Handle the ARM float format.
8071 if (!BitConverter.IsLittleEndian)
8072 System.Array.Reverse (data, idx, 8);
8074 case BuiltinTypeSpec.Type.Char:
8075 int chval = (int) ((char) v);
8077 data[idx] = (byte) (chval & 0xff);
8078 data[idx + 1] = (byte) (chval >> 8);
8080 case BuiltinTypeSpec.Type.Short:
8081 int sval = (int) ((short) v);
8083 data[idx] = (byte) (sval & 0xff);
8084 data[idx + 1] = (byte) (sval >> 8);
8086 case BuiltinTypeSpec.Type.UShort:
8087 int usval = (int) ((ushort) v);
8089 data[idx] = (byte) (usval & 0xff);
8090 data[idx + 1] = (byte) (usval >> 8);
8092 case BuiltinTypeSpec.Type.Int:
8095 data[idx] = (byte) (val & 0xff);
8096 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8097 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8098 data[idx + 3] = (byte) (val >> 24);
8100 case BuiltinTypeSpec.Type.UInt:
8101 uint uval = (uint) v;
8103 data[idx] = (byte) (uval & 0xff);
8104 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8105 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8106 data[idx + 3] = (byte) (uval >> 24);
8108 case BuiltinTypeSpec.Type.SByte:
8109 data[idx] = (byte) (sbyte) v;
8111 case BuiltinTypeSpec.Type.Byte:
8112 data[idx] = (byte) v;
8114 case BuiltinTypeSpec.Type.Bool:
8115 data[idx] = (byte) ((bool) v ? 1 : 0);
8117 case BuiltinTypeSpec.Type.Decimal:
8118 int[] bits = Decimal.GetBits ((decimal) v);
8121 // FIXME: For some reason, this doesn't work on the MS runtime.
8122 int[] nbits = new int[4];
8128 for (int j = 0; j < 4; j++) {
8129 data[p++] = (byte) (nbits[j] & 0xff);
8130 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8131 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8132 data[p++] = (byte) (nbits[j] >> 24);
8136 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8145 #if NET_4_0 || MOBILE_DYNAMIC
8146 public override SLE.Expression MakeExpression (BuilderContext ctx)
8149 return base.MakeExpression (ctx);
8151 var initializers = new SLE.Expression [array_data.Count];
8152 for (var i = 0; i < initializers.Length; i++) {
8153 if (array_data [i] == null)
8154 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8156 initializers [i] = array_data [i].MakeExpression (ctx);
8159 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8165 // Emits the initializers for the array
8167 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8169 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8174 // First, the static data
8176 byte [] data = MakeByteBlob ();
8177 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8179 if (stackArray == null) {
8180 ec.Emit (OpCodes.Dup);
8182 stackArray.Emit (ec);
8185 ec.Emit (OpCodes.Ldtoken, fb);
8186 ec.Emit (OpCodes.Call, m);
8191 // Emits pieces of the array that can not be computed at compile
8192 // time (variables and string locations).
8194 // This always expect the top value on the stack to be the array
8196 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8198 int dims = bounds.Count;
8199 var current_pos = new int [dims];
8201 for (int i = 0; i < array_data.Count; i++){
8203 Expression e = array_data [i];
8204 var c = e as Constant;
8206 // Constant can be initialized via StaticInitializer
8207 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8211 if (stackArray != null) {
8212 if (e.ContainsEmitWithAwait ()) {
8213 e = e.EmitToField (ec);
8216 stackArray.EmitLoad (ec);
8218 ec.Emit (OpCodes.Dup);
8221 for (int idx = 0; idx < dims; idx++)
8222 ec.EmitInt (current_pos [idx]);
8225 // If we are dealing with a struct, get the
8226 // address of it, so we can store it.
8228 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8229 ec.Emit (OpCodes.Ldelema, etype);
8233 ec.EmitArrayStore ((ArrayContainer) type);
8239 for (int j = dims - 1; j >= 0; j--){
8241 if (current_pos [j] < bounds [j])
8243 current_pos [j] = 0;
8247 if (stackArray != null)
8248 stackArray.PrepareCleanup (ec);
8251 public override void Emit (EmitContext ec)
8253 var await_field = EmitToFieldSource (ec);
8254 if (await_field != null)
8255 await_field.Emit (ec);
8258 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8260 if (first_emit != null) {
8261 first_emit.Emit (ec);
8262 first_emit_temp.Store (ec);
8265 StackFieldExpr await_stack_field;
8266 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8267 await_stack_field = ec.GetTemporaryField (type);
8270 await_stack_field = null;
8273 EmitExpressionsList (ec, arguments);
8275 ec.EmitArrayNew ((ArrayContainer) type);
8277 if (initializers == null)
8278 return await_stack_field;
8280 if (await_stack_field != null)
8281 await_stack_field.EmitAssignFromStack (ec);
8285 // Emit static initializer for arrays which contain more than 2 items and
8286 // the static initializer will initialize at least 25% of array values or there
8287 // is more than 10 items to be initialized
8289 // NOTE: const_initializers_count does not contain default constant values.
8291 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8292 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8293 EmitStaticInitializers (ec, await_stack_field);
8295 if (!only_constant_initializers)
8296 EmitDynamicInitializers (ec, false, await_stack_field);
8300 EmitDynamicInitializers (ec, true, await_stack_field);
8303 if (first_emit_temp != null)
8304 first_emit_temp.Release (ec);
8306 return await_stack_field;
8309 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8311 // no multi dimensional or jagged arrays
8312 if (arguments.Count != 1 || array_element_type.IsArray) {
8313 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8317 // No array covariance, except for array -> object
8318 if (type != targetType) {
8319 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8320 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8324 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8325 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8330 // Single dimensional array of 0 size
8331 if (array_data == null) {
8332 IntConstant ic = arguments[0] as IntConstant;
8333 if (ic == null || !ic.IsDefaultValue) {
8334 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8342 enc.Encode (array_data.Count);
8343 foreach (var element in array_data) {
8344 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8348 protected override void CloneTo (CloneContext clonectx, Expression t)
8350 ArrayCreation target = (ArrayCreation) t;
8352 if (requested_base_type != null)
8353 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8355 if (arguments != null){
8356 target.arguments = new List<Expression> (arguments.Count);
8357 foreach (Expression e in arguments)
8358 target.arguments.Add (e.Clone (clonectx));
8361 if (initializers != null)
8362 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8365 public override object Accept (StructuralVisitor visitor)
8367 return visitor.Visit (this);
8372 // Represents an implicitly typed array epxression
8374 class ImplicitlyTypedArrayCreation : ArrayCreation
8376 TypeInferenceContext best_type_inference;
8378 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8379 : base (null, rank, initializers, loc)
8383 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8384 : base (null, initializers, loc)
8388 protected override Expression DoResolve (ResolveContext ec)
8393 dimensions = rank.Dimension;
8395 best_type_inference = new TypeInferenceContext ();
8397 if (!ResolveInitializers (ec))
8400 best_type_inference.FixAllTypes (ec);
8401 array_element_type = best_type_inference.InferredTypeArguments[0];
8402 best_type_inference = null;
8404 if (array_element_type == null ||
8405 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8406 arguments.Count != rank.Dimension) {
8407 ec.Report.Error (826, loc,
8408 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8413 // At this point we found common base type for all initializer elements
8414 // but we have to be sure that all static initializer elements are of
8417 UnifyInitializerElement (ec);
8419 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8420 eclass = ExprClass.Value;
8425 // Converts static initializer only
8427 void UnifyInitializerElement (ResolveContext ec)
8429 for (int i = 0; i < array_data.Count; ++i) {
8430 Expression e = array_data[i];
8432 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8436 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8438 element = element.Resolve (ec);
8439 if (element != null)
8440 best_type_inference.AddCommonTypeBound (element.Type);
8446 sealed class CompilerGeneratedThis : This
8448 public CompilerGeneratedThis (TypeSpec type, Location loc)
8454 protected override Expression DoResolve (ResolveContext rc)
8456 eclass = ExprClass.Variable;
8458 var block = rc.CurrentBlock;
8459 if (block != null) {
8460 var top = block.ParametersBlock.TopBlock;
8461 if (top.ThisVariable != null)
8462 variable_info = top.ThisVariable.VariableInfo;
8469 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8471 return DoResolve (rc);
8474 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8481 /// Represents the `this' construct
8484 public class This : VariableReference
8486 sealed class ThisVariable : ILocalVariable
8488 public static readonly ILocalVariable Instance = new ThisVariable ();
8490 public void Emit (EmitContext ec)
8495 public void EmitAssign (EmitContext ec)
8497 throw new InvalidOperationException ();
8500 public void EmitAddressOf (EmitContext ec)
8506 protected VariableInfo variable_info;
8508 public This (Location loc)
8515 public override string Name {
8516 get { return "this"; }
8519 public override bool IsLockedByStatement {
8527 public override bool IsRef {
8528 get { return type.IsStruct; }
8531 public override bool IsSideEffectFree {
8537 protected override ILocalVariable Variable {
8538 get { return ThisVariable.Instance; }
8541 public override VariableInfo VariableInfo {
8542 get { return variable_info; }
8545 public override bool IsFixed {
8546 get { return false; }
8551 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8554 // It's null for all cases when we don't need to check `this'
8555 // definitive assignment
8557 if (variable_info == null)
8560 if (fc.IsDefinitelyAssigned (variable_info))
8563 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8566 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8568 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8569 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8570 } else if (ec.CurrentAnonymousMethod != null) {
8571 ec.Report.Error (1673, loc,
8572 "Anonymous methods inside structs cannot access instance members of `this'. " +
8573 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8575 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8579 public override void FlowAnalysis (FlowAnalysisContext fc)
8581 CheckStructThisDefiniteAssignment (fc);
8584 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8589 AnonymousMethodStorey storey = ae.Storey;
8590 return storey != null ? storey.HoistedThis : null;
8593 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8595 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8598 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8601 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8607 public virtual void ResolveBase (ResolveContext ec)
8609 eclass = ExprClass.Variable;
8610 type = ec.CurrentType;
8612 if (!IsThisAvailable (ec, false)) {
8613 Error_ThisNotAvailable (ec);
8617 var block = ec.CurrentBlock;
8618 if (block != null) {
8619 var top = block.ParametersBlock.TopBlock;
8620 if (top.ThisVariable != null)
8621 variable_info = top.ThisVariable.VariableInfo;
8623 AnonymousExpression am = ec.CurrentAnonymousMethod;
8624 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8626 // Hoisted this is almost like hoisted variable but not exactly. When
8627 // there is no variable hoisted we can simply emit an instance method
8628 // without lifting this into a storey. Unfotunatelly this complicates
8629 // things in other cases because we don't know where this will be hoisted
8630 // until top-level block is fully resolved
8632 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8633 am.SetHasThisAccess ();
8638 protected override Expression DoResolve (ResolveContext ec)
8644 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8646 if (eclass == ExprClass.Unresolved)
8650 if (right_side == EmptyExpression.UnaryAddress)
8651 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8652 else if (right_side == EmptyExpression.OutAccess)
8653 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8655 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8661 public override int GetHashCode()
8663 throw new NotImplementedException ();
8666 public override bool Equals (object obj)
8668 This t = obj as This;
8675 protected override void CloneTo (CloneContext clonectx, Expression t)
8680 public override void SetHasAddressTaken ()
8685 public override object Accept (StructuralVisitor visitor)
8687 return visitor.Visit (this);
8692 /// Represents the `__arglist' construct
8694 public class ArglistAccess : Expression
8696 public ArglistAccess (Location loc)
8701 protected override void CloneTo (CloneContext clonectx, Expression target)
8706 public override bool ContainsEmitWithAwait ()
8711 public override Expression CreateExpressionTree (ResolveContext ec)
8713 throw new NotSupportedException ("ET");
8716 protected override Expression DoResolve (ResolveContext ec)
8718 eclass = ExprClass.Variable;
8719 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8721 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8722 ec.Report.Error (190, loc,
8723 "The __arglist construct is valid only within a variable argument method");
8729 public override void Emit (EmitContext ec)
8731 ec.Emit (OpCodes.Arglist);
8734 public override object Accept (StructuralVisitor visitor)
8736 return visitor.Visit (this);
8741 /// Represents the `__arglist (....)' construct
8743 public class Arglist : Expression
8745 Arguments arguments;
8747 public Arglist (Location loc)
8752 public Arglist (Arguments args, Location l)
8758 public Arguments Arguments {
8764 public MetaType[] ArgumentTypes {
8766 if (arguments == null)
8767 return MetaType.EmptyTypes;
8769 var retval = new MetaType[arguments.Count];
8770 for (int i = 0; i < retval.Length; i++)
8771 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8777 public override bool ContainsEmitWithAwait ()
8779 throw new NotImplementedException ();
8782 public override Expression CreateExpressionTree (ResolveContext ec)
8784 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8788 protected override Expression DoResolve (ResolveContext ec)
8790 eclass = ExprClass.Variable;
8791 type = InternalType.Arglist;
8792 if (arguments != null) {
8793 bool dynamic; // Can be ignored as there is always only 1 overload
8794 arguments.Resolve (ec, out dynamic);
8800 public override void Emit (EmitContext ec)
8802 if (arguments != null)
8803 arguments.Emit (ec);
8806 protected override void CloneTo (CloneContext clonectx, Expression t)
8808 Arglist target = (Arglist) t;
8810 if (arguments != null)
8811 target.arguments = arguments.Clone (clonectx);
8814 public override object Accept (StructuralVisitor visitor)
8816 return visitor.Visit (this);
8820 public class RefValueExpr : ShimExpression, IAssignMethod
8822 FullNamedExpression texpr;
8824 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8831 public FullNamedExpression TypeExpression {
8837 public override bool ContainsEmitWithAwait ()
8842 protected override Expression DoResolve (ResolveContext rc)
8844 expr = expr.Resolve (rc);
8845 type = texpr.ResolveAsType (rc);
8846 if (expr == null || type == null)
8849 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8850 eclass = ExprClass.Value;
8854 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8856 return DoResolve (rc);
8859 public override void Emit (EmitContext ec)
8862 ec.Emit (OpCodes.Refanyval, type);
8863 ec.EmitLoadFromPtr (type);
8866 public void Emit (EmitContext ec, bool leave_copy)
8868 throw new NotImplementedException ();
8871 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8874 ec.Emit (OpCodes.Refanyval, type);
8877 LocalTemporary temporary = null;
8879 ec.Emit (OpCodes.Dup);
8880 temporary = new LocalTemporary (source.Type);
8881 temporary.Store (ec);
8884 ec.EmitStoreFromPtr (type);
8886 if (temporary != null) {
8887 temporary.Emit (ec);
8888 temporary.Release (ec);
8892 public override object Accept (StructuralVisitor visitor)
8894 return visitor.Visit (this);
8898 public class RefTypeExpr : ShimExpression
8900 public RefTypeExpr (Expression expr, Location loc)
8906 protected override Expression DoResolve (ResolveContext rc)
8908 expr = expr.Resolve (rc);
8912 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8916 type = rc.BuiltinTypes.Type;
8917 eclass = ExprClass.Value;
8921 public override void Emit (EmitContext ec)
8924 ec.Emit (OpCodes.Refanytype);
8925 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8927 ec.Emit (OpCodes.Call, m);
8930 public override object Accept (StructuralVisitor visitor)
8932 return visitor.Visit (this);
8936 public class MakeRefExpr : ShimExpression
8938 public MakeRefExpr (Expression expr, Location loc)
8944 public override bool ContainsEmitWithAwait ()
8946 throw new NotImplementedException ();
8949 protected override Expression DoResolve (ResolveContext rc)
8951 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8952 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8953 eclass = ExprClass.Value;
8957 public override void Emit (EmitContext ec)
8959 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8960 ec.Emit (OpCodes.Mkrefany, expr.Type);
8963 public override object Accept (StructuralVisitor visitor)
8965 return visitor.Visit (this);
8970 /// Implements the typeof operator
8972 public class TypeOf : Expression {
8973 FullNamedExpression QueriedType;
8976 public TypeOf (FullNamedExpression queried_type, Location l)
8978 QueriedType = queried_type;
8983 // Use this constructor for any compiler generated typeof expression
8985 public TypeOf (TypeSpec type, Location loc)
8987 this.typearg = type;
8993 public override bool IsSideEffectFree {
8999 public TypeSpec TypeArgument {
9005 public FullNamedExpression TypeExpression {
9014 protected override void CloneTo (CloneContext clonectx, Expression t)
9016 TypeOf target = (TypeOf) t;
9017 if (QueriedType != null)
9018 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9021 public override bool ContainsEmitWithAwait ()
9026 public override Expression CreateExpressionTree (ResolveContext ec)
9028 Arguments args = new Arguments (2);
9029 args.Add (new Argument (this));
9030 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9031 return CreateExpressionFactoryCall (ec, "Constant", args);
9034 protected override Expression DoResolve (ResolveContext ec)
9036 if (eclass != ExprClass.Unresolved)
9039 if (typearg == null) {
9041 // Pointer types are allowed without explicit unsafe, they are just tokens
9043 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9044 typearg = QueriedType.ResolveAsType (ec, true);
9047 if (typearg == null)
9050 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9051 ec.Report.Error (1962, QueriedType.Location,
9052 "The typeof operator cannot be used on the dynamic type");
9056 type = ec.BuiltinTypes.Type;
9058 // Even though what is returned is a type object, it's treated as a value by the compiler.
9059 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9060 eclass = ExprClass.Value;
9064 static bool ContainsDynamicType (TypeSpec type)
9066 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9069 var element_container = type as ElementTypeSpec;
9070 if (element_container != null)
9071 return ContainsDynamicType (element_container.Element);
9073 foreach (var t in type.TypeArguments) {
9074 if (ContainsDynamicType (t)) {
9082 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9084 // Target type is not System.Type therefore must be object
9085 // and we need to use different encoding sequence
9086 if (targetType != type)
9089 if (typearg is InflatedTypeSpec) {
9092 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9093 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9094 typearg.GetSignatureForError ());
9098 gt = gt.DeclaringType;
9099 } while (gt != null);
9102 if (ContainsDynamicType (typearg)) {
9103 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9107 enc.EncodeTypeName (typearg);
9110 public override void Emit (EmitContext ec)
9112 ec.Emit (OpCodes.Ldtoken, typearg);
9113 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9115 ec.Emit (OpCodes.Call, m);
9118 public override object Accept (StructuralVisitor visitor)
9120 return visitor.Visit (this);
9124 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9126 public TypeOfMethod (MethodSpec method, Location loc)
9127 : base (method, loc)
9131 protected override Expression DoResolve (ResolveContext ec)
9133 if (member.IsConstructor) {
9134 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9136 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9142 return base.DoResolve (ec);
9145 public override void Emit (EmitContext ec)
9147 ec.Emit (OpCodes.Ldtoken, member);
9150 ec.Emit (OpCodes.Castclass, type);
9153 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9155 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9158 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9160 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9164 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9166 protected readonly T member;
9168 protected TypeOfMember (T member, Location loc)
9170 this.member = member;
9174 public override bool IsSideEffectFree {
9180 public override bool ContainsEmitWithAwait ()
9185 public override Expression CreateExpressionTree (ResolveContext ec)
9187 Arguments args = new Arguments (2);
9188 args.Add (new Argument (this));
9189 args.Add (new Argument (new TypeOf (type, loc)));
9190 return CreateExpressionFactoryCall (ec, "Constant", args);
9193 protected override Expression DoResolve (ResolveContext ec)
9195 eclass = ExprClass.Value;
9199 public override void Emit (EmitContext ec)
9201 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9202 PredefinedMember<MethodSpec> p;
9204 p = GetTypeFromHandleGeneric (ec);
9205 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9207 p = GetTypeFromHandle (ec);
9210 var mi = p.Resolve (loc);
9212 ec.Emit (OpCodes.Call, mi);
9215 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9216 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9219 sealed class TypeOfField : TypeOfMember<FieldSpec>
9221 public TypeOfField (FieldSpec field, Location loc)
9226 protected override Expression DoResolve (ResolveContext ec)
9228 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9232 return base.DoResolve (ec);
9235 public override void Emit (EmitContext ec)
9237 ec.Emit (OpCodes.Ldtoken, member);
9241 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9243 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9246 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9248 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9253 /// Implements the sizeof expression
9255 public class SizeOf : Expression {
9256 readonly Expression texpr;
9257 TypeSpec type_queried;
9259 public SizeOf (Expression queried_type, Location l)
9261 this.texpr = queried_type;
9265 public override bool IsSideEffectFree {
9271 public Expression TypeExpression {
9277 public override bool ContainsEmitWithAwait ()
9282 public override Expression CreateExpressionTree (ResolveContext ec)
9284 Error_PointerInsideExpressionTree (ec);
9288 protected override Expression DoResolve (ResolveContext ec)
9290 type_queried = texpr.ResolveAsType (ec);
9291 if (type_queried == null)
9294 if (type_queried.IsEnum)
9295 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9297 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9299 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9302 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9307 ec.Report.Error (233, loc,
9308 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9309 type_queried.GetSignatureForError ());
9312 type = ec.BuiltinTypes.Int;
9313 eclass = ExprClass.Value;
9317 public override void Emit (EmitContext ec)
9319 ec.Emit (OpCodes.Sizeof, type_queried);
9322 protected override void CloneTo (CloneContext clonectx, Expression t)
9326 public override object Accept (StructuralVisitor visitor)
9328 return visitor.Visit (this);
9333 /// Implements the qualified-alias-member (::) expression.
9335 public class QualifiedAliasMember : MemberAccess
9337 readonly string alias;
9338 public static readonly string GlobalAlias = "global";
9340 public QualifiedAliasMember (string alias, string identifier, Location l)
9341 : base (null, identifier, l)
9346 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9347 : base (null, identifier, targs, l)
9352 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9353 : base (null, identifier, arity, l)
9358 public string Alias {
9364 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9366 if (alias == GlobalAlias)
9367 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9369 int errors = mc.Module.Compiler.Report.Errors;
9370 var expr = mc.LookupNamespaceAlias (alias);
9372 if (errors == mc.Module.Compiler.Report.Errors)
9373 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9381 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9383 expr = CreateExpressionFromAlias (mc);
9387 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9390 protected override Expression DoResolve (ResolveContext rc)
9392 return ResolveAsTypeOrNamespace (rc, false);
9395 public override string GetSignatureForError ()
9398 if (targs != null) {
9399 name = Name + "<" + targs.GetSignatureForError () + ">";
9402 return alias + "::" + name;
9405 public override bool HasConditionalAccess ()
9410 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9412 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9413 rc.Module.Compiler.Report.Error (687, loc,
9414 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9415 GetSignatureForError ());
9420 return DoResolve (rc);
9423 protected override void CloneTo (CloneContext clonectx, Expression t)
9428 public override object Accept (StructuralVisitor visitor)
9430 return visitor.Visit (this);
9435 /// Implements the member access expression
9437 public class MemberAccess : ATypeNameExpression
9439 protected Expression expr;
9441 public MemberAccess (Expression expr, string id)
9442 : base (id, expr.Location)
9447 public MemberAccess (Expression expr, string identifier, Location loc)
9448 : base (identifier, loc)
9453 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9454 : base (identifier, args, loc)
9459 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9460 : base (identifier, arity, loc)
9465 public Expression LeftExpression {
9471 public override Location StartLocation {
9473 return expr == null ? loc : expr.StartLocation;
9477 protected override Expression DoResolve (ResolveContext rc)
9479 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9481 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9486 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9488 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9490 if (e is TypeExpr) {
9491 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9496 e = e.ResolveLValue (rc, rhs);
9501 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9503 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9504 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9506 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9509 public override bool HasConditionalAccess ()
9511 return LeftExpression.HasConditionalAccess ();
9514 public static bool IsValidDotExpression (TypeSpec type)
9516 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9517 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9519 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9522 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9524 var sn = expr as SimpleName;
9525 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9528 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9531 // Resolve expression which does have type set as we need expression type
9532 // with disable flow analysis as we don't know whether left side expression
9533 // is used as variable or type
9535 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9536 expr = expr.Resolve (rc);
9537 } else if (expr is TypeParameterExpr) {
9538 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9542 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9543 expr = expr.Resolve (rc, flags);
9550 var ns = expr as NamespaceExpression;
9552 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9554 if (retval == null) {
9555 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
9559 if (HasTypeArguments)
9560 return new GenericTypeExpr (retval.Type, targs, loc);
9566 TypeSpec expr_type = expr.Type;
9567 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9568 me = expr as MemberExpr;
9570 me.ResolveInstanceExpression (rc, null);
9572 Arguments args = new Arguments (1);
9573 args.Add (new Argument (expr));
9574 return new DynamicMemberBinder (Name, args, loc);
9577 var cma = this as ConditionalMemberAccess;
9579 if (!IsNullPropagatingValid (expr.Type)) {
9580 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9584 if (expr_type.IsNullableType) {
9585 expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
9586 expr_type = expr.Type;
9590 if (!IsValidDotExpression (expr_type)) {
9591 Error_OperatorCannotBeApplied (rc, expr_type);
9595 var lookup_arity = Arity;
9596 bool errorMode = false;
9597 Expression member_lookup;
9599 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9600 if (member_lookup == null) {
9602 // Try to look for extension method when member lookup failed
9604 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9605 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
9606 if (methods != null) {
9607 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9608 if (HasTypeArguments) {
9609 if (!targs.Resolve (rc))
9612 emg.SetTypeArguments (rc, targs);
9616 emg.ConditionalAccess = true;
9618 // TODO: it should really skip the checks bellow
9619 return emg.Resolve (rc);
9625 if (member_lookup == null) {
9626 var dep = expr_type.GetMissingDependencies ();
9628 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9629 } else if (expr is TypeExpr) {
9630 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9632 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9638 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9639 // Leave it to overload resolution to report correct error
9640 } else if (!(member_lookup is TypeExpr)) {
9641 // TODO: rc.SymbolRelatedToPreviousError
9642 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9647 if (member_lookup != null)
9651 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9655 TypeExpr texpr = member_lookup as TypeExpr;
9656 if (texpr != null) {
9657 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9658 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9659 Name, texpr.GetSignatureForError ());
9662 if (!texpr.Type.IsAccessible (rc)) {
9663 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9664 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9668 if (HasTypeArguments) {
9669 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9672 return member_lookup;
9675 me = member_lookup as MemberExpr;
9677 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9682 me.ConditionalAccess = true;
9685 me = me.ResolveMemberAccess (rc, expr, sn);
9688 if (!targs.Resolve (rc))
9691 me.SetTypeArguments (rc, targs);
9697 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9699 FullNamedExpression fexpr = expr as FullNamedExpression;
9700 if (fexpr == null) {
9701 expr.ResolveAsType (rc);
9705 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9707 if (expr_resolved == null)
9710 var ns = expr_resolved as NamespaceExpression;
9712 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9714 if (retval == null) {
9715 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
9716 } else if (Arity > 0) {
9717 if (HasTypeArguments) {
9718 retval = new GenericTypeExpr (retval.Type, targs, loc);
9719 if (retval.ResolveAsType (rc) == null)
9722 if (!allowUnboundTypeArguments)
9723 Error_OpenGenericTypeIsNotAllowed (rc);
9725 retval = new GenericOpenTypeExpr (retval.Type, loc);
9732 var tnew_expr = expr_resolved.ResolveAsType (rc);
9733 if (tnew_expr == null)
9736 TypeSpec expr_type = tnew_expr;
9737 if (TypeManager.IsGenericParameter (expr_type)) {
9738 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9739 tnew_expr.GetSignatureForError ());
9743 var qam = this as QualifiedAliasMember;
9745 rc.Module.Compiler.Report.Error (431, loc,
9746 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9751 TypeSpec nested = null;
9752 while (expr_type != null) {
9753 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9754 if (nested == null) {
9755 if (expr_type == tnew_expr) {
9756 Error_IdentifierNotFound (rc, expr_type);
9760 expr_type = tnew_expr;
9761 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9762 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9766 if (nested.IsAccessible (rc))
9770 // Keep looking after inaccessible candidate but only if
9771 // we are not in same context as the definition itself
9773 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9776 expr_type = expr_type.BaseType;
9781 if (HasTypeArguments) {
9782 texpr = new GenericTypeExpr (nested, targs, loc);
9784 if (!allowUnboundTypeArguments || expr_resolved is GenericTypeExpr) // && HasTypeArguments
9785 Error_OpenGenericTypeIsNotAllowed (rc);
9787 texpr = new GenericOpenTypeExpr (nested, loc);
9789 } else if (expr_resolved is GenericOpenTypeExpr) {
9790 texpr = new GenericOpenTypeExpr (nested, loc);
9792 texpr = new TypeExpression (nested, loc);
9795 if (texpr.ResolveAsType (rc) == null)
9801 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9803 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9805 if (nested != null) {
9806 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9810 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9811 if (any_other_member != null) {
9812 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9816 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9817 Name, expr_type.GetSignatureForError ());
9820 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9822 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9825 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9827 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9828 ec.Report.SymbolRelatedToPreviousError (type);
9830 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9832 // a using directive or an assembly reference
9834 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9836 missing = "an assembly reference";
9839 ec.Report.Error (1061, loc,
9840 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9841 type.GetSignatureForError (), name, missing);
9845 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9848 public override string GetSignatureForError ()
9850 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9853 protected override void CloneTo (CloneContext clonectx, Expression t)
9855 MemberAccess target = (MemberAccess) t;
9857 target.expr = expr.Clone (clonectx);
9860 public override object Accept (StructuralVisitor visitor)
9862 return visitor.Visit (this);
9866 public class ConditionalMemberAccess : MemberAccess
9868 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9869 : base (expr, identifier, args, loc)
9873 public override bool HasConditionalAccess ()
9880 /// Implements checked expressions
9882 public class CheckedExpr : Expression {
9884 public Expression Expr;
9886 public CheckedExpr (Expression e, Location l)
9892 public override bool ContainsEmitWithAwait ()
9894 return Expr.ContainsEmitWithAwait ();
9897 public override Expression CreateExpressionTree (ResolveContext ec)
9899 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9900 return Expr.CreateExpressionTree (ec);
9903 protected override Expression DoResolve (ResolveContext ec)
9905 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9906 Expr = Expr.Resolve (ec);
9911 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9914 eclass = Expr.eclass;
9919 public override void Emit (EmitContext ec)
9921 using (ec.With (EmitContext.Options.CheckedScope, true))
9925 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9927 using (ec.With (EmitContext.Options.CheckedScope, true))
9928 Expr.EmitBranchable (ec, target, on_true);
9931 public override void FlowAnalysis (FlowAnalysisContext fc)
9933 Expr.FlowAnalysis (fc);
9936 public override SLE.Expression MakeExpression (BuilderContext ctx)
9938 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9939 return Expr.MakeExpression (ctx);
9943 protected override void CloneTo (CloneContext clonectx, Expression t)
9945 CheckedExpr target = (CheckedExpr) t;
9947 target.Expr = Expr.Clone (clonectx);
9950 public override object Accept (StructuralVisitor visitor)
9952 return visitor.Visit (this);
9957 /// Implements the unchecked expression
9959 public class UnCheckedExpr : Expression {
9961 public Expression Expr;
9963 public UnCheckedExpr (Expression e, Location l)
9969 public override bool ContainsEmitWithAwait ()
9971 return Expr.ContainsEmitWithAwait ();
9974 public override Expression CreateExpressionTree (ResolveContext ec)
9976 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9977 return Expr.CreateExpressionTree (ec);
9980 protected override Expression DoResolve (ResolveContext ec)
9982 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9983 Expr = Expr.Resolve (ec);
9988 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9991 eclass = Expr.eclass;
9996 public override void Emit (EmitContext ec)
9998 using (ec.With (EmitContext.Options.CheckedScope, false))
10002 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10004 using (ec.With (EmitContext.Options.CheckedScope, false))
10005 Expr.EmitBranchable (ec, target, on_true);
10008 public override void FlowAnalysis (FlowAnalysisContext fc)
10010 Expr.FlowAnalysis (fc);
10013 protected override void CloneTo (CloneContext clonectx, Expression t)
10015 UnCheckedExpr target = (UnCheckedExpr) t;
10017 target.Expr = Expr.Clone (clonectx);
10020 public override object Accept (StructuralVisitor visitor)
10022 return visitor.Visit (this);
10027 /// An Element Access expression.
10029 /// During semantic analysis these are transformed into
10030 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10032 public class ElementAccess : Expression
10034 public Arguments Arguments;
10035 public Expression Expr;
10037 public ElementAccess (Expression e, Arguments args, Location loc)
10041 this.Arguments = args;
10044 public bool ConditionalAccess { get; set; }
10046 public override Location StartLocation {
10048 return Expr.StartLocation;
10052 public override bool ContainsEmitWithAwait ()
10054 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10058 // We perform some simple tests, and then to "split" the emit and store
10059 // code we create an instance of a different class, and return that.
10061 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10063 Expr = Expr.Resolve (ec);
10069 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10070 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10075 return new ArrayAccess (this, loc) {
10076 ConditionalAccess = ConditionalAccess,
10077 ConditionalAccessReceiver = conditionalAccessReceiver
10080 if (type.IsPointer)
10081 return MakePointerAccess (ec, type);
10083 FieldExpr fe = Expr as FieldExpr;
10085 var ff = fe.Spec as FixedFieldSpec;
10087 return MakePointerAccess (ec, ff.ElementType);
10091 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10092 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10093 var indexer = new IndexerExpr (indexers, type, this) {
10094 ConditionalAccess = ConditionalAccess
10097 if (conditionalAccessReceiver)
10098 indexer.SetConditionalAccessReceiver ();
10103 Error_CannotApplyIndexing (ec, type, loc);
10108 public override Expression CreateExpressionTree (ResolveContext ec)
10110 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10111 Expr.CreateExpressionTree (ec));
10113 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10116 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10118 if (type != InternalType.ErrorType) {
10119 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10120 type.GetSignatureForError ());
10124 public override bool HasConditionalAccess ()
10126 return ConditionalAccess || Expr.HasConditionalAccess ();
10129 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
10131 if (Arguments.Count != 1){
10132 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
10136 var arg = Arguments[0];
10137 if (arg is NamedArgument)
10138 Error_NamedArgument ((NamedArgument) arg, rc.Report);
10140 var index = arg.Expr.Resolve (rc);
10144 index = ConvertExpressionToArrayIndex (rc, index, true);
10146 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
10147 return new Indirection (p, loc);
10150 protected override Expression DoResolve (ResolveContext rc)
10153 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10154 if (HasConditionalAccess ()) {
10155 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10156 expr = CreateAccessExpression (rc, true);
10160 return expr.Resolve (rc);
10165 expr = CreateAccessExpression (rc, false);
10169 return expr.Resolve (rc);
10172 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10174 var res = CreateAccessExpression (ec, false);
10178 return res.ResolveLValue (ec, rhs);
10181 public override void Emit (EmitContext ec)
10183 throw new Exception ("Should never be reached");
10186 public static void Error_NamedArgument (NamedArgument na, Report Report)
10188 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
10191 public override void FlowAnalysis (FlowAnalysisContext fc)
10193 Expr.FlowAnalysis (fc);
10195 if (ConditionalAccess)
10196 fc.BranchConditionalAccessDefiniteAssignment ();
10198 Arguments.FlowAnalysis (fc);
10201 public override string GetSignatureForError ()
10203 return Expr.GetSignatureForError ();
10206 protected override void CloneTo (CloneContext clonectx, Expression t)
10208 ElementAccess target = (ElementAccess) t;
10210 target.Expr = Expr.Clone (clonectx);
10211 if (Arguments != null)
10212 target.Arguments = Arguments.Clone (clonectx);
10215 public override object Accept (StructuralVisitor visitor)
10217 return visitor.Visit (this);
10222 /// Implements array access
10224 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10226 // Points to our "data" repository
10230 LocalTemporary temp;
10232 bool? has_await_args;
10234 public ArrayAccess (ElementAccess ea_data, Location l)
10240 public bool ConditionalAccess { get; set; }
10242 public bool ConditionalAccessReceiver { get; set; }
10244 public void AddressOf (EmitContext ec, AddressOp mode)
10246 var ac = (ArrayContainer) ea.Expr.Type;
10248 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10249 LoadInstanceAndArguments (ec, false, true);
10252 LoadInstanceAndArguments (ec, false, false);
10254 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10255 ec.Emit (OpCodes.Readonly);
10257 ec.EmitArrayAddress (ac);
10260 public override Expression CreateExpressionTree (ResolveContext ec)
10262 if (ConditionalAccess)
10263 Error_NullShortCircuitInsideExpressionTree (ec);
10265 return ea.CreateExpressionTree (ec);
10268 public override bool ContainsEmitWithAwait ()
10270 return ea.ContainsEmitWithAwait ();
10273 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10275 if (ConditionalAccess)
10276 throw new NotSupportedException ("null propagating operator assignment");
10278 return DoResolve (ec);
10281 protected override Expression DoResolve (ResolveContext ec)
10283 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10285 ea.Arguments.Resolve (ec, out dynamic);
10287 var ac = ea.Expr.Type as ArrayContainer;
10288 int rank = ea.Arguments.Count;
10289 if (ac.Rank != rank) {
10290 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10291 rank.ToString (), ac.Rank.ToString ());
10296 if (type.IsPointer && !ec.IsUnsafe) {
10297 UnsafeError (ec, ea.Location);
10300 if (ConditionalAccessReceiver)
10301 type = LiftMemberType (ec, type);
10303 foreach (Argument a in ea.Arguments) {
10304 var na = a as NamedArgument;
10306 ElementAccess.Error_NamedArgument (na, ec.Report);
10308 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10311 eclass = ExprClass.Variable;
10316 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10318 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10321 public override void FlowAnalysis (FlowAnalysisContext fc)
10323 ea.FlowAnalysis (fc);
10327 // Load the array arguments into the stack.
10329 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10331 if (prepareAwait) {
10332 ea.Expr = ea.Expr.EmitToField (ec);
10334 var ie = new InstanceEmitter (ea.Expr, false);
10335 ie.Emit (ec, ConditionalAccess);
10337 if (duplicateArguments) {
10338 ec.Emit (OpCodes.Dup);
10340 var copy = new LocalTemporary (ea.Expr.Type);
10346 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10347 if (dup_args != null)
10348 ea.Arguments = dup_args;
10351 public void Emit (EmitContext ec, bool leave_copy)
10354 ec.EmitLoadFromPtr (type);
10356 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10357 LoadInstanceAndArguments (ec, false, true);
10360 if (ConditionalAccessReceiver)
10361 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10363 var ac = (ArrayContainer) ea.Expr.Type;
10364 LoadInstanceAndArguments (ec, false, false);
10365 ec.EmitArrayLoad (ac);
10367 if (ConditionalAccessReceiver)
10368 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10372 ec.Emit (OpCodes.Dup);
10373 temp = new LocalTemporary (this.type);
10378 public override void Emit (EmitContext ec)
10383 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10385 var ac = (ArrayContainer) ea.Expr.Type;
10386 TypeSpec t = source.Type;
10388 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10391 // When we are dealing with a struct, get the address of it to avoid value copy
10392 // Same cannot be done for reference type because array covariance and the
10393 // check in ldelema requires to specify the type of array element stored at the index
10395 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10396 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10398 if (has_await_args.Value) {
10399 if (source.ContainsEmitWithAwait ()) {
10400 source = source.EmitToField (ec);
10401 isCompound = false;
10405 LoadInstanceAndArguments (ec, isCompound, false);
10410 ec.EmitArrayAddress (ac);
10413 ec.Emit (OpCodes.Dup);
10417 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10419 if (has_await_args.Value) {
10420 if (source.ContainsEmitWithAwait ())
10421 source = source.EmitToField (ec);
10423 LoadInstanceAndArguments (ec, false, false);
10430 var lt = ea.Expr as LocalTemporary;
10436 ec.Emit (OpCodes.Dup);
10437 temp = new LocalTemporary (this.type);
10442 ec.EmitStoreFromPtr (t);
10444 ec.EmitArrayStore (ac);
10447 if (temp != null) {
10453 public override Expression EmitToField (EmitContext ec)
10456 // Have to be specialized for arrays to get access to
10457 // underlying element. Instead of another result copy we
10458 // need direct access to element
10462 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10464 ea.Expr = ea.Expr.EmitToField (ec);
10465 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10469 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10471 #if NET_4_0 || MOBILE_DYNAMIC
10472 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10474 throw new NotImplementedException ();
10478 public override SLE.Expression MakeExpression (BuilderContext ctx)
10480 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10483 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10485 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10486 return Arguments.MakeExpression (ea.Arguments, ctx);
10492 // Indexer access expression
10494 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10496 IList<MemberSpec> indexers;
10497 Arguments arguments;
10498 TypeSpec queried_type;
10500 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10501 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10505 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10508 this.indexers = indexers;
10509 this.queried_type = queriedType;
10510 this.InstanceExpression = instance;
10511 this.arguments = args;
10516 protected override Arguments Arguments {
10525 protected override TypeSpec DeclaringType {
10527 return best_candidate.DeclaringType;
10531 public override bool IsInstance {
10537 public override bool IsStatic {
10543 public override string KindName {
10544 get { return "indexer"; }
10547 public override string Name {
10555 public override bool ContainsEmitWithAwait ()
10557 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10560 public override Expression CreateExpressionTree (ResolveContext ec)
10562 if (ConditionalAccess) {
10563 Error_NullShortCircuitInsideExpressionTree (ec);
10566 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10567 InstanceExpression.CreateExpressionTree (ec),
10568 new TypeOfMethod (Getter, loc));
10570 return CreateExpressionFactoryCall (ec, "Call", args);
10573 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10575 LocalTemporary await_source_arg = null;
10578 emitting_compound_assignment = true;
10579 if (source is DynamicExpressionStatement) {
10584 emitting_compound_assignment = false;
10586 if (has_await_arguments) {
10587 await_source_arg = new LocalTemporary (Type);
10588 await_source_arg.Store (ec);
10590 arguments.Add (new Argument (await_source_arg));
10593 temp = await_source_arg;
10596 has_await_arguments = false;
10601 ec.Emit (OpCodes.Dup);
10602 temp = new LocalTemporary (Type);
10608 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10609 source = source.EmitToField (ec);
10611 temp = new LocalTemporary (Type);
10618 arguments.Add (new Argument (source));
10621 var call = new CallEmitter ();
10622 call.InstanceExpression = InstanceExpression;
10623 if (arguments == null)
10624 call.InstanceExpressionOnStack = true;
10626 call.Emit (ec, Setter, arguments, loc);
10628 if (temp != null) {
10631 } else if (leave_copy) {
10635 if (await_source_arg != null) {
10636 await_source_arg.Release (ec);
10640 public override void FlowAnalysis (FlowAnalysisContext fc)
10642 base.FlowAnalysis (fc);
10643 arguments.FlowAnalysis (fc);
10645 if (conditional_access_receiver)
10646 fc.ConditionalAccessEnd ();
10649 public override string GetSignatureForError ()
10651 return best_candidate.GetSignatureForError ();
10654 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10657 throw new NotSupportedException ();
10659 var value = new[] { source.MakeExpression (ctx) };
10660 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10661 #if NET_4_0 || MOBILE_DYNAMIC
10662 return SLE.Expression.Block (
10663 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10666 return args.First ();
10671 public override SLE.Expression MakeExpression (BuilderContext ctx)
10674 return base.MakeExpression (ctx);
10676 var args = Arguments.MakeExpression (arguments, ctx);
10677 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10681 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10683 if (best_candidate != null)
10686 eclass = ExprClass.IndexerAccess;
10689 arguments.Resolve (rc, out dynamic);
10691 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10694 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10695 res.BaseMembersProvider = this;
10696 res.InstanceQualifier = this;
10698 // TODO: Do I need 2 argument sets?
10699 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10700 if (best_candidate != null)
10701 type = res.BestCandidateReturnType;
10702 else if (!res.BestCandidateIsDynamic)
10707 // It has dynamic arguments
10710 Arguments args = new Arguments (arguments.Count + 1);
10712 rc.Report.Error (1972, loc,
10713 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10715 args.Add (new Argument (InstanceExpression));
10717 args.AddRange (arguments);
10719 best_candidate = null;
10720 return new DynamicIndexBinder (args, loc);
10724 // Try to avoid resolving left expression again
10726 if (right_side != null)
10727 ResolveInstanceExpression (rc, right_side);
10732 protected override void CloneTo (CloneContext clonectx, Expression t)
10734 IndexerExpr target = (IndexerExpr) t;
10736 if (arguments != null)
10737 target.arguments = arguments.Clone (clonectx);
10740 public void SetConditionalAccessReceiver ()
10742 conditional_access_receiver = true;
10745 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10747 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10750 #region IBaseMembersProvider Members
10752 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10754 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10757 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10759 if (queried_type == member.DeclaringType)
10762 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10763 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10766 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10775 // A base access expression
10777 public class BaseThis : This
10779 public BaseThis (Location loc)
10784 public BaseThis (TypeSpec type, Location loc)
10788 eclass = ExprClass.Variable;
10793 public override string Name {
10801 public override Expression CreateExpressionTree (ResolveContext ec)
10803 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10804 return base.CreateExpressionTree (ec);
10807 public override void Emit (EmitContext ec)
10811 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10812 var context_type = ec.CurrentType;
10813 ec.Emit (OpCodes.Ldobj, context_type);
10814 ec.Emit (OpCodes.Box, context_type);
10818 protected override void Error_ThisNotAvailable (ResolveContext ec)
10821 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10823 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10827 public override void ResolveBase (ResolveContext ec)
10829 base.ResolveBase (ec);
10830 type = ec.CurrentType.BaseType;
10833 public override object Accept (StructuralVisitor visitor)
10835 return visitor.Visit (this);
10840 /// This class exists solely to pass the Type around and to be a dummy
10841 /// that can be passed to the conversion functions (this is used by
10842 /// foreach implementation to typecast the object return value from
10843 /// get_Current into the proper type. All code has been generated and
10844 /// we only care about the side effect conversions to be performed
10846 /// This is also now used as a placeholder where a no-action expression
10847 /// is needed (the `New' class).
10849 public class EmptyExpression : Expression
10851 sealed class OutAccessExpression : EmptyExpression
10853 public OutAccessExpression (TypeSpec t)
10858 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10860 rc.Report.Error (206, right_side.Location,
10861 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10867 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10868 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10869 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10870 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10871 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10872 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10873 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10874 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10876 public EmptyExpression (TypeSpec t)
10879 eclass = ExprClass.Value;
10880 loc = Location.Null;
10883 protected override void CloneTo (CloneContext clonectx, Expression target)
10887 public override bool ContainsEmitWithAwait ()
10892 public override Expression CreateExpressionTree (ResolveContext ec)
10894 throw new NotSupportedException ("ET");
10897 protected override Expression DoResolve (ResolveContext ec)
10902 public override void Emit (EmitContext ec)
10904 // nothing, as we only exist to not do anything.
10907 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10911 public override void EmitSideEffect (EmitContext ec)
10915 public override object Accept (StructuralVisitor visitor)
10917 return visitor.Visit (this);
10921 sealed class EmptyAwaitExpression : EmptyExpression
10923 public EmptyAwaitExpression (TypeSpec type)
10928 public override bool ContainsEmitWithAwait ()
10935 // Empty statement expression
10937 public sealed class EmptyExpressionStatement : ExpressionStatement
10939 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10941 private EmptyExpressionStatement ()
10943 loc = Location.Null;
10946 public override bool ContainsEmitWithAwait ()
10951 public override Expression CreateExpressionTree (ResolveContext ec)
10956 public override void EmitStatement (EmitContext ec)
10961 protected override Expression DoResolve (ResolveContext ec)
10963 eclass = ExprClass.Value;
10964 type = ec.BuiltinTypes.Object;
10968 public override void Emit (EmitContext ec)
10973 public override object Accept (StructuralVisitor visitor)
10975 return visitor.Visit (this);
10979 public class ErrorExpression : EmptyExpression
10981 public static readonly ErrorExpression Instance = new ErrorExpression ();
10983 private ErrorExpression ()
10984 : base (InternalType.ErrorType)
10988 public override Expression CreateExpressionTree (ResolveContext ec)
10993 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10998 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11002 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11006 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11010 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11014 public override object Accept (StructuralVisitor visitor)
11016 return visitor.Visit (this);
11020 public class UserCast : Expression {
11024 public UserCast (MethodSpec method, Expression source, Location l)
11026 if (source == null)
11027 throw new ArgumentNullException ("source");
11029 this.method = method;
11030 this.source = source;
11031 type = method.ReturnType;
11035 public Expression Source {
11041 public override bool ContainsEmitWithAwait ()
11043 return source.ContainsEmitWithAwait ();
11046 public override Expression CreateExpressionTree (ResolveContext ec)
11048 Arguments args = new Arguments (3);
11049 args.Add (new Argument (source.CreateExpressionTree (ec)));
11050 args.Add (new Argument (new TypeOf (type, loc)));
11051 args.Add (new Argument (new TypeOfMethod (method, loc)));
11052 return CreateExpressionFactoryCall (ec, "Convert", args);
11055 protected override Expression DoResolve (ResolveContext ec)
11057 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11059 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11061 eclass = ExprClass.Value;
11065 public override void Emit (EmitContext ec)
11068 ec.MarkCallEntry (loc);
11069 ec.Emit (OpCodes.Call, method);
11072 public override void FlowAnalysis (FlowAnalysisContext fc)
11074 source.FlowAnalysis (fc);
11077 public override string GetSignatureForError ()
11079 return TypeManager.CSharpSignature (method);
11082 public override SLE.Expression MakeExpression (BuilderContext ctx)
11085 return base.MakeExpression (ctx);
11087 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11093 // Holds additional type specifiers like ?, *, []
11095 public class ComposedTypeSpecifier
11097 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11099 public readonly int Dimension;
11100 public readonly Location Location;
11102 public ComposedTypeSpecifier (int specifier, Location loc)
11104 this.Dimension = specifier;
11105 this.Location = loc;
11109 public bool IsNullable {
11111 return Dimension == -1;
11115 public bool IsPointer {
11117 return Dimension == -2;
11121 public ComposedTypeSpecifier Next { get; set; }
11125 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11127 return new ComposedTypeSpecifier (dimension, loc);
11130 public static ComposedTypeSpecifier CreateNullable (Location loc)
11132 return new ComposedTypeSpecifier (-1, loc);
11135 public static ComposedTypeSpecifier CreatePointer (Location loc)
11137 return new ComposedTypeSpecifier (-2, loc);
11140 public string GetSignatureForError ()
11145 ArrayContainer.GetPostfixSignature (Dimension);
11147 return Next != null ? s + Next.GetSignatureForError () : s;
11152 // This class is used to "construct" the type during a typecast
11153 // operation. Since the Type.GetType class in .NET can parse
11154 // the type specification, we just use this to construct the type
11155 // one bit at a time.
11157 public class ComposedCast : TypeExpr {
11158 FullNamedExpression left;
11159 ComposedTypeSpecifier spec;
11161 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11164 throw new ArgumentNullException ("spec");
11168 this.loc = left.Location;
11171 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11173 type = left.ResolveAsType (ec);
11177 eclass = ExprClass.Type;
11179 var single_spec = spec;
11181 if (single_spec.IsNullable) {
11182 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11186 single_spec = single_spec.Next;
11187 } else if (single_spec.IsPointer) {
11188 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11191 if (!ec.IsUnsafe) {
11192 UnsafeError (ec.Module.Compiler.Report, loc);
11196 type = PointerContainer.MakeType (ec.Module, type);
11197 single_spec = single_spec.Next;
11198 } while (single_spec != null && single_spec.IsPointer);
11201 if (single_spec != null && single_spec.Dimension > 0) {
11202 if (type.IsSpecialRuntimeType) {
11203 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11204 } else if (type.IsStatic) {
11205 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11206 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11207 type.GetSignatureForError ());
11209 MakeArray (ec.Module, single_spec);
11216 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11218 if (spec.Next != null)
11219 MakeArray (module, spec.Next);
11221 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11224 public override string GetSignatureForError ()
11226 return left.GetSignatureForError () + spec.GetSignatureForError ();
11229 public override object Accept (StructuralVisitor visitor)
11231 return visitor.Visit (this);
11235 class FixedBufferPtr : Expression
11237 readonly Expression array;
11239 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11241 this.type = array_type;
11242 this.array = array;
11246 public override bool ContainsEmitWithAwait ()
11248 throw new NotImplementedException ();
11251 public override Expression CreateExpressionTree (ResolveContext ec)
11253 Error_PointerInsideExpressionTree (ec);
11257 public override void Emit(EmitContext ec)
11262 protected override Expression DoResolve (ResolveContext ec)
11264 type = PointerContainer.MakeType (ec.Module, type);
11265 eclass = ExprClass.Value;
11272 // This class is used to represent the address of an array, used
11273 // only by the Fixed statement, this generates "&a [0]" construct
11274 // for fixed (char *pa = a)
11276 class ArrayPtr : FixedBufferPtr
11278 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11279 base (array, array_type, l)
11283 public override void Emit (EmitContext ec)
11288 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11293 // Encapsulates a conversion rules required for array indexes
11295 public class ArrayIndexCast : TypeCast
11297 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11298 : base (expr, returnType)
11300 if (expr.Type == returnType) // int -> int
11301 throw new ArgumentException ("unnecessary array index conversion");
11304 public override Expression CreateExpressionTree (ResolveContext ec)
11306 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11307 return base.CreateExpressionTree (ec);
11311 public override void Emit (EmitContext ec)
11315 switch (child.Type.BuiltinType) {
11316 case BuiltinTypeSpec.Type.UInt:
11317 ec.Emit (OpCodes.Conv_U);
11319 case BuiltinTypeSpec.Type.Long:
11320 ec.Emit (OpCodes.Conv_Ovf_I);
11322 case BuiltinTypeSpec.Type.ULong:
11323 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11326 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11332 // Implements the `stackalloc' keyword
11334 public class StackAlloc : Expression {
11339 public StackAlloc (Expression type, Expression count, Location l)
11342 this.count = count;
11346 public Expression TypeExpression {
11352 public Expression CountExpression {
11358 public override bool ContainsEmitWithAwait ()
11363 public override Expression CreateExpressionTree (ResolveContext ec)
11365 throw new NotSupportedException ("ET");
11368 protected override Expression DoResolve (ResolveContext ec)
11370 count = count.Resolve (ec);
11374 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11375 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11380 Constant c = count as Constant;
11381 if (c != null && c.IsNegative) {
11382 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11385 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11386 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11389 otype = t.ResolveAsType (ec);
11393 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11396 type = PointerContainer.MakeType (ec.Module, otype);
11397 eclass = ExprClass.Value;
11402 public override void Emit (EmitContext ec)
11404 int size = BuiltinTypeSpec.GetSize (otype);
11409 ec.Emit (OpCodes.Sizeof, otype);
11413 ec.Emit (OpCodes.Mul_Ovf_Un);
11414 ec.Emit (OpCodes.Localloc);
11417 protected override void CloneTo (CloneContext clonectx, Expression t)
11419 StackAlloc target = (StackAlloc) t;
11420 target.count = count.Clone (clonectx);
11421 target.t = t.Clone (clonectx);
11424 public override object Accept (StructuralVisitor visitor)
11426 return visitor.Visit (this);
11431 // An object initializer expression
11433 public class ElementInitializer : Assign
11435 public readonly string Name;
11437 public ElementInitializer (string name, Expression initializer, Location loc)
11438 : base (null, initializer, loc)
11443 public bool IsDictionaryInitializer {
11445 return Name == null;
11449 protected override void CloneTo (CloneContext clonectx, Expression t)
11451 ElementInitializer target = (ElementInitializer) t;
11452 target.source = source.Clone (clonectx);
11455 public override Expression CreateExpressionTree (ResolveContext ec)
11457 Arguments args = new Arguments (2);
11458 FieldExpr fe = target as FieldExpr;
11460 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11462 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11465 Expression arg_expr;
11466 var cinit = source as CollectionOrObjectInitializers;
11467 if (cinit == null) {
11469 arg_expr = source.CreateExpressionTree (ec);
11471 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11472 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11475 args.Add (new Argument (arg_expr));
11476 return CreateExpressionFactoryCall (ec, mname, args);
11479 protected override Expression DoResolve (ResolveContext ec)
11481 if (source == null)
11482 return EmptyExpressionStatement.Instance;
11484 if (!ResolveElement (ec))
11487 if (source is CollectionOrObjectInitializers) {
11488 Expression previous = ec.CurrentInitializerVariable;
11489 ec.CurrentInitializerVariable = target;
11490 source = source.Resolve (ec);
11491 ec.CurrentInitializerVariable = previous;
11492 if (source == null)
11495 eclass = source.eclass;
11496 type = source.Type;
11500 return base.DoResolve (ec);
11503 public override void EmitStatement (EmitContext ec)
11505 if (source is CollectionOrObjectInitializers)
11508 base.EmitStatement (ec);
11511 protected virtual bool ResolveElement (ResolveContext rc)
11513 var t = rc.CurrentInitializerVariable.Type;
11514 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11515 Arguments args = new Arguments (1);
11516 args.Add (new Argument (rc.CurrentInitializerVariable));
11517 target = new DynamicMemberBinder (Name, args, loc);
11520 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11521 if (member == null) {
11522 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11524 if (member != null) {
11525 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11526 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11531 if (member == null) {
11532 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11536 var me = member as MemberExpr;
11537 if (me is EventExpr) {
11538 me = me.ResolveMemberAccess (rc, null, null);
11539 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11540 rc.Report.Error (1913, loc,
11541 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11542 member.GetSignatureForError ());
11548 rc.Report.Error (1914, loc,
11549 "Static field or property `{0}' cannot be assigned in an object initializer",
11550 me.GetSignatureForError ());
11554 me.InstanceExpression = rc.CurrentInitializerVariable;
11562 // A collection initializer expression
11564 class CollectionElementInitializer : Invocation
11566 public class ElementInitializerArgument : Argument
11568 public ElementInitializerArgument (Expression e)
11574 sealed class AddMemberAccess : MemberAccess
11576 public AddMemberAccess (Expression expr, Location loc)
11577 : base (expr, "Add", loc)
11581 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11583 if (TypeManager.HasElementType (type))
11586 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11590 public CollectionElementInitializer (Expression argument)
11591 : base (null, new Arguments (1))
11593 base.arguments.Add (new ElementInitializerArgument (argument));
11594 this.loc = argument.Location;
11597 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11598 : base (null, new Arguments (arguments.Count))
11600 foreach (Expression e in arguments)
11601 base.arguments.Add (new ElementInitializerArgument (e));
11606 public CollectionElementInitializer (Location loc)
11607 : base (null, null)
11612 public override Expression CreateExpressionTree (ResolveContext ec)
11614 Arguments args = new Arguments (2);
11615 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11617 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11618 foreach (Argument a in arguments)
11619 expr_initializers.Add (a.CreateExpressionTree (ec));
11621 args.Add (new Argument (new ArrayCreation (
11622 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11623 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11626 protected override void CloneTo (CloneContext clonectx, Expression t)
11628 CollectionElementInitializer target = (CollectionElementInitializer) t;
11629 if (arguments != null)
11630 target.arguments = arguments.Clone (clonectx);
11633 protected override Expression DoResolve (ResolveContext ec)
11635 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11637 return base.DoResolve (ec);
11641 class DictionaryElementInitializer : ElementInitializer
11643 readonly Arguments args;
11645 public DictionaryElementInitializer (List<Expression> arguments, Expression initializer, Location loc)
11646 : base (null, initializer, loc)
11648 this.args = new Arguments (arguments.Count);
11649 foreach (var arg in arguments)
11650 this.args.Add (new Argument (arg));
11653 public override Expression CreateExpressionTree (ResolveContext ec)
11655 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11659 protected override bool ResolveElement (ResolveContext rc)
11661 var init = rc.CurrentInitializerVariable;
11662 var type = init.Type;
11664 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11665 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11666 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11670 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11676 // A block of object or collection initializers
11678 public class CollectionOrObjectInitializers : ExpressionStatement
11680 IList<Expression> initializers;
11681 bool is_collection_initialization;
11683 public CollectionOrObjectInitializers (Location loc)
11684 : this (new Expression[0], loc)
11688 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11690 this.initializers = initializers;
11694 public IList<Expression> Initializers {
11696 return initializers;
11700 public bool IsEmpty {
11702 return initializers.Count == 0;
11706 public bool IsCollectionInitializer {
11708 return is_collection_initialization;
11712 protected override void CloneTo (CloneContext clonectx, Expression target)
11714 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11716 t.initializers = new List<Expression> (initializers.Count);
11717 foreach (var e in initializers)
11718 t.initializers.Add (e.Clone (clonectx));
11721 public override bool ContainsEmitWithAwait ()
11723 foreach (var e in initializers) {
11724 if (e.ContainsEmitWithAwait ())
11731 public override Expression CreateExpressionTree (ResolveContext ec)
11733 return CreateExpressionTree (ec, false);
11736 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11738 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11739 foreach (Expression e in initializers) {
11740 Expression expr = e.CreateExpressionTree (ec);
11742 expr_initializers.Add (expr);
11746 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11748 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11751 protected override Expression DoResolve (ResolveContext ec)
11753 List<string> element_names = null;
11754 for (int i = 0; i < initializers.Count; ++i) {
11755 Expression initializer = initializers [i];
11756 ElementInitializer element_initializer = initializer as ElementInitializer;
11759 if (element_initializer != null) {
11760 element_names = new List<string> (initializers.Count);
11761 if (!element_initializer.IsDictionaryInitializer)
11762 element_names.Add (element_initializer.Name);
11763 } else if (initializer is CompletingExpression) {
11764 initializer.Resolve (ec);
11765 throw new InternalErrorException ("This line should never be reached");
11767 var t = ec.CurrentInitializerVariable.Type;
11768 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11769 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11770 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11771 "object initializer because type `{1}' does not implement `{2}' interface",
11772 ec.CurrentInitializerVariable.GetSignatureForError (),
11773 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11774 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11777 is_collection_initialization = true;
11780 if (is_collection_initialization != (element_initializer == null)) {
11781 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11782 is_collection_initialization ? "collection initializer" : "object initializer");
11786 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11787 if (element_names.Contains (element_initializer.Name)) {
11788 ec.Report.Error (1912, element_initializer.Location,
11789 "An object initializer includes more than one member `{0}' initialization",
11790 element_initializer.Name);
11792 element_names.Add (element_initializer.Name);
11797 Expression e = initializer.Resolve (ec);
11798 if (e == EmptyExpressionStatement.Instance)
11799 initializers.RemoveAt (i--);
11801 initializers [i] = e;
11804 type = ec.CurrentInitializerVariable.Type;
11805 if (is_collection_initialization) {
11806 if (TypeManager.HasElementType (type)) {
11807 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11808 type.GetSignatureForError ());
11812 eclass = ExprClass.Variable;
11816 public override void Emit (EmitContext ec)
11818 EmitStatement (ec);
11821 public override void EmitStatement (EmitContext ec)
11823 foreach (ExpressionStatement e in initializers) {
11824 // TODO: need location region
11825 ec.Mark (e.Location);
11826 e.EmitStatement (ec);
11830 public override void FlowAnalysis (FlowAnalysisContext fc)
11832 foreach (var initializer in initializers) {
11833 if (initializer != null)
11834 initializer.FlowAnalysis (fc);
11840 // New expression with element/object initializers
11842 public class NewInitialize : New
11845 // This class serves as a proxy for variable initializer target instances.
11846 // A real variable is assigned later when we resolve left side of an
11849 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11851 NewInitialize new_instance;
11853 public InitializerTargetExpression (NewInitialize newInstance)
11855 this.type = newInstance.type;
11856 this.loc = newInstance.loc;
11857 this.eclass = newInstance.eclass;
11858 this.new_instance = newInstance;
11861 public override bool ContainsEmitWithAwait ()
11866 public override Expression CreateExpressionTree (ResolveContext ec)
11868 // Should not be reached
11869 throw new NotSupportedException ("ET");
11872 protected override Expression DoResolve (ResolveContext ec)
11877 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
11882 public override void Emit (EmitContext ec)
11884 Expression e = (Expression) new_instance.instance;
11888 public override Expression EmitToField (EmitContext ec)
11890 return (Expression) new_instance.instance;
11893 #region IMemoryLocation Members
11895 public void AddressOf (EmitContext ec, AddressOp mode)
11897 new_instance.instance.AddressOf (ec, mode);
11903 CollectionOrObjectInitializers initializers;
11904 IMemoryLocation instance;
11905 DynamicExpressionStatement dynamic;
11907 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
11908 : base (requested_type, arguments, l)
11910 this.initializers = initializers;
11913 public CollectionOrObjectInitializers Initializers {
11915 return initializers;
11919 protected override void CloneTo (CloneContext clonectx, Expression t)
11921 base.CloneTo (clonectx, t);
11923 NewInitialize target = (NewInitialize) t;
11924 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
11927 public override bool ContainsEmitWithAwait ()
11929 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
11932 public override Expression CreateExpressionTree (ResolveContext ec)
11934 Arguments args = new Arguments (2);
11935 args.Add (new Argument (base.CreateExpressionTree (ec)));
11936 if (!initializers.IsEmpty)
11937 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
11939 return CreateExpressionFactoryCall (ec,
11940 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
11944 protected override Expression DoResolve (ResolveContext ec)
11946 Expression e = base.DoResolve (ec);
11950 if (type.IsDelegate) {
11951 ec.Report.Error (1958, Initializers.Location,
11952 "Object and collection initializers cannot be used to instantiate a delegate");
11955 Expression previous = ec.CurrentInitializerVariable;
11956 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
11957 initializers.Resolve (ec);
11958 ec.CurrentInitializerVariable = previous;
11960 dynamic = e as DynamicExpressionStatement;
11961 if (dynamic != null)
11967 public override void Emit (EmitContext ec)
11969 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11970 var fe = ec.GetTemporaryField (type);
11972 if (!Emit (ec, fe))
11981 public override bool Emit (EmitContext ec, IMemoryLocation target)
11983 bool left_on_stack;
11984 if (dynamic != null) {
11986 left_on_stack = true;
11988 left_on_stack = base.Emit (ec, target);
11991 if (initializers.IsEmpty)
11992 return left_on_stack;
11994 LocalTemporary temp = null;
11996 instance = target as LocalTemporary;
11997 if (instance == null)
11998 instance = target as StackFieldExpr;
12000 if (instance == null) {
12001 if (!left_on_stack) {
12002 VariableReference vr = target as VariableReference;
12004 // FIXME: This still does not work correctly for pre-set variables
12005 if (vr != null && vr.IsRef)
12006 target.AddressOf (ec, AddressOp.Load);
12008 ((Expression) target).Emit (ec);
12009 left_on_stack = true;
12012 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12013 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
12015 temp = new LocalTemporary (type);
12020 if (left_on_stack && temp != null)
12023 initializers.Emit (ec);
12025 if (left_on_stack) {
12026 if (temp != null) {
12030 ((Expression) instance).Emit (ec);
12034 return left_on_stack;
12037 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12039 instance = base.EmitAddressOf (ec, Mode);
12041 if (!initializers.IsEmpty)
12042 initializers.Emit (ec);
12047 public override void FlowAnalysis (FlowAnalysisContext fc)
12049 base.FlowAnalysis (fc);
12050 initializers.FlowAnalysis (fc);
12053 public override object Accept (StructuralVisitor visitor)
12055 return visitor.Visit (this);
12059 public class NewAnonymousType : New
12061 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12063 List<AnonymousTypeParameter> parameters;
12064 readonly TypeContainer parent;
12065 AnonymousTypeClass anonymous_type;
12067 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12068 : base (null, null, loc)
12070 this.parameters = parameters;
12071 this.parent = parent;
12074 public List<AnonymousTypeParameter> Parameters {
12076 return this.parameters;
12080 protected override void CloneTo (CloneContext clonectx, Expression target)
12082 if (parameters == null)
12085 NewAnonymousType t = (NewAnonymousType) target;
12086 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12087 foreach (AnonymousTypeParameter atp in parameters)
12088 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12091 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12093 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12097 type = AnonymousTypeClass.Create (parent, parameters, loc);
12101 int errors = ec.Report.Errors;
12102 type.CreateContainer ();
12103 type.DefineContainer ();
12105 if ((ec.Report.Errors - errors) == 0) {
12106 parent.Module.AddAnonymousType (type);
12107 type.PrepareEmit ();
12113 public override Expression CreateExpressionTree (ResolveContext ec)
12115 if (parameters == null)
12116 return base.CreateExpressionTree (ec);
12118 var init = new ArrayInitializer (parameters.Count, loc);
12119 foreach (var m in anonymous_type.Members) {
12120 var p = m as Property;
12122 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12125 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12126 foreach (Argument a in arguments)
12127 ctor_args.Add (a.CreateExpressionTree (ec));
12129 Arguments args = new Arguments (3);
12130 args.Add (new Argument (new TypeOfMethod (method, loc)));
12131 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12132 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12134 return CreateExpressionFactoryCall (ec, "New", args);
12137 protected override Expression DoResolve (ResolveContext ec)
12139 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12140 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12144 if (parameters == null) {
12145 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12146 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12147 return base.DoResolve (ec);
12150 bool error = false;
12151 arguments = new Arguments (parameters.Count);
12152 var t_args = new TypeSpec [parameters.Count];
12153 for (int i = 0; i < parameters.Count; ++i) {
12154 Expression e = parameters [i].Resolve (ec);
12160 arguments.Add (new Argument (e));
12161 t_args [i] = e.Type;
12167 anonymous_type = CreateAnonymousType (ec, parameters);
12168 if (anonymous_type == null)
12171 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12172 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12173 eclass = ExprClass.Value;
12177 public override object Accept (StructuralVisitor visitor)
12179 return visitor.Visit (this);
12183 public class AnonymousTypeParameter : ShimExpression
12185 public readonly string Name;
12187 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12188 : base (initializer)
12194 public AnonymousTypeParameter (Parameter parameter)
12195 : base (new SimpleName (parameter.Name, parameter.Location))
12197 this.Name = parameter.Name;
12198 this.loc = parameter.Location;
12201 public override bool Equals (object o)
12203 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12204 return other != null && Name == other.Name;
12207 public override int GetHashCode ()
12209 return Name.GetHashCode ();
12212 protected override Expression DoResolve (ResolveContext ec)
12214 Expression e = expr.Resolve (ec);
12218 if (e.eclass == ExprClass.MethodGroup) {
12219 Error_InvalidInitializer (ec, e.ExprClassName);
12224 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12225 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12232 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12234 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12235 Name, initializer);
12239 public class CatchFilterExpression : BooleanExpression
12241 public CatchFilterExpression (Expression expr, Location loc)