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);
2497 public class DeclarationExpression : Expression, IMemoryLocation
2499 LocalVariableReference lvr;
2501 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2503 VariableType = variableType;
2504 Variable = variable;
2505 this.loc = variable.Location;
2508 public LocalVariable Variable { get; set; }
2509 public Expression Initializer { get; set; }
2510 public FullNamedExpression VariableType { get; set; }
2512 public void AddressOf (EmitContext ec, AddressOp mode)
2514 Variable.CreateBuilder (ec);
2516 if (Initializer != null) {
2517 lvr.EmitAssign (ec, Initializer, false, false);
2520 lvr.AddressOf (ec, mode);
2523 protected override void CloneTo (CloneContext clonectx, Expression t)
2525 var target = (DeclarationExpression) t;
2527 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2529 if (Initializer != null)
2530 target.Initializer = Initializer.Clone (clonectx);
2533 public override Expression CreateExpressionTree (ResolveContext rc)
2535 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2539 bool DoResolveCommon (ResolveContext rc)
2541 var var_expr = VariableType as VarExpr;
2542 if (var_expr != null) {
2543 type = InternalType.VarOutType;
2545 type = VariableType.ResolveAsType (rc);
2550 if (Initializer != null) {
2551 Initializer = Initializer.Resolve (rc);
2553 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2554 type = var_expr.Type;
2558 Variable.Type = type;
2559 lvr = new LocalVariableReference (Variable, loc);
2561 eclass = ExprClass.Variable;
2565 protected override Expression DoResolve (ResolveContext rc)
2567 if (DoResolveCommon (rc))
2573 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2575 if (lvr == null && DoResolveCommon (rc))
2576 lvr.ResolveLValue (rc, right_side);
2581 public override void Emit (EmitContext ec)
2583 throw new NotImplementedException ();
2588 // C# 2.0 Default value expression
2590 public class DefaultValueExpression : Expression
2594 public DefaultValueExpression (Expression expr, Location loc)
2600 public Expression Expr {
2606 public override bool IsSideEffectFree {
2612 public override bool ContainsEmitWithAwait ()
2617 public override Expression CreateExpressionTree (ResolveContext ec)
2619 Arguments args = new Arguments (2);
2620 args.Add (new Argument (this));
2621 args.Add (new Argument (new TypeOf (type, loc)));
2622 return CreateExpressionFactoryCall (ec, "Constant", args);
2625 protected override Expression DoResolve (ResolveContext ec)
2627 type = expr.ResolveAsType (ec);
2631 if (type.IsStatic) {
2632 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2636 return new NullLiteral (Location).ConvertImplicitly (type);
2638 if (TypeSpec.IsReferenceType (type))
2639 return new NullConstant (type, loc);
2641 Constant c = New.Constantify (type, expr.Location);
2645 eclass = ExprClass.Variable;
2649 public override void Emit (EmitContext ec)
2651 LocalTemporary temp_storage = new LocalTemporary(type);
2653 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2654 ec.Emit(OpCodes.Initobj, type);
2655 temp_storage.Emit(ec);
2656 temp_storage.Release (ec);
2659 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
2660 public override SLE.Expression MakeExpression (BuilderContext ctx)
2662 return SLE.Expression.Default (type.GetMetaInfo ());
2666 protected override void CloneTo (CloneContext clonectx, Expression t)
2668 DefaultValueExpression target = (DefaultValueExpression) t;
2670 target.expr = expr.Clone (clonectx);
2673 public override object Accept (StructuralVisitor visitor)
2675 return visitor.Visit (this);
2680 /// Binary operators
2682 public class Binary : Expression, IDynamicBinder
2684 public class PredefinedOperator
2686 protected readonly TypeSpec left;
2687 protected readonly TypeSpec right;
2688 protected readonly TypeSpec left_unwrap;
2689 protected readonly TypeSpec right_unwrap;
2690 public readonly Operator OperatorsMask;
2691 public TypeSpec ReturnType;
2693 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2694 : this (ltype, rtype, op_mask, ltype)
2698 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2699 : this (type, type, op_mask, return_type)
2703 public PredefinedOperator (TypeSpec type, Operator op_mask)
2704 : this (type, type, op_mask, type)
2708 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2710 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2711 throw new InternalErrorException ("Only masked values can be used");
2713 if ((op_mask & Operator.NullableMask) != 0) {
2714 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2715 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2717 left_unwrap = ltype;
2718 right_unwrap = rtype;
2723 this.OperatorsMask = op_mask;
2724 this.ReturnType = return_type;
2727 public bool IsLifted {
2729 return (OperatorsMask & Operator.NullableMask) != 0;
2733 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2737 var left_expr = b.left;
2738 var right_expr = b.right;
2740 b.type = ReturnType;
2743 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2744 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2745 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2748 if (right_expr.IsNull) {
2749 if ((b.oper & Operator.EqualityMask) != 0) {
2750 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2751 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2752 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2753 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2754 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2756 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2757 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2759 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2760 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2762 return b.CreateLiftedValueTypeResult (rc, left);
2764 } else if (left_expr.IsNull) {
2765 if ((b.oper & Operator.EqualityMask) != 0) {
2766 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2767 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2768 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2769 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2770 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2772 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2773 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2775 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2776 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2778 return b.CreateLiftedValueTypeResult (rc, right);
2784 // A user operators does not support multiple user conversions, but decimal type
2785 // is considered to be predefined type therefore we apply predefined operators rules
2786 // and then look for decimal user-operator implementation
2788 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2789 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2790 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2792 return b.ResolveUserOperator (rc, b.left, b.right);
2795 c = right_expr as Constant;
2797 if (c.IsDefaultValue) {
2801 // (expr + 0) to expr
2802 // (expr - 0) to expr
2803 // (bool? | false) to bool?
2805 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2806 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2807 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2808 return ReducedExpression.Create (b.left, b).Resolve (rc);
2812 // Optimizes (value &/&& 0) to 0
2814 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2815 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2816 return ReducedExpression.Create (side_effect, b);
2820 // Optimizes (bool? & true) to bool?
2822 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2823 return ReducedExpression.Create (b.left, b).Resolve (rc);
2827 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2828 return ReducedExpression.Create (b.left, b).Resolve (rc);
2830 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2831 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2835 c = b.left as Constant;
2837 if (c.IsDefaultValue) {
2841 // (0 + expr) to expr
2842 // (false | bool?) to bool?
2844 if (b.oper == Operator.Addition ||
2845 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2846 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2847 return ReducedExpression.Create (b.right, b).Resolve (rc);
2851 // Optimizes (false && expr) to false
2853 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2854 // No rhs side-effects
2855 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2856 return ReducedExpression.Create (c, b);
2860 // Optimizes (0 & value) to 0
2862 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2863 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2864 return ReducedExpression.Create (side_effect, b);
2868 // Optimizes (true & bool?) to bool?
2870 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2871 return ReducedExpression.Create (b.right, b).Resolve (rc);
2875 // Optimizes (true || expr) to true
2877 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2878 // No rhs side-effects
2879 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2880 return ReducedExpression.Create (c, b);
2884 if (b.oper == Operator.Multiply && c.IsOneInteger)
2885 return ReducedExpression.Create (b.right, b).Resolve (rc);
2889 var lifted = new Nullable.LiftedBinaryOperator (b);
2891 TypeSpec ltype, rtype;
2892 if (b.left.Type.IsNullableType) {
2893 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2894 ltype = left_unwrap;
2899 if (b.right.Type.IsNullableType) {
2900 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2901 rtype = right_unwrap;
2906 lifted.Left = b.left.IsNull ?
2908 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2910 lifted.Right = b.right.IsNull ?
2912 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2914 return lifted.Resolve (rc);
2917 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2918 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2923 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2926 // We are dealing with primitive types only
2928 return left == ltype && ltype == rtype;
2931 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2934 if (left == lexpr.Type && right == rexpr.Type)
2937 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2938 Convert.ImplicitConversionExists (ec, rexpr, right);
2941 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2943 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2944 return best_operator;
2946 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2950 if (left != null && best_operator.left != null) {
2951 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2955 // When second argument is same as the first one, the result is same
2957 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2958 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2961 if (result == 0 || result > 2)
2964 return result == 1 ? best_operator : this;
2968 sealed class PredefinedStringOperator : PredefinedOperator
2970 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2971 : base (type, type, op_mask, retType)
2975 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2976 : base (ltype, rtype, op_mask, retType)
2980 public override Expression ConvertResult (ResolveContext ec, Binary b)
2983 // Use original expression for nullable arguments
2985 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2987 b.left = unwrap.Original;
2989 unwrap = b.right as Nullable.Unwrap;
2991 b.right = unwrap.Original;
2993 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2994 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2997 // Start a new concat expression using converted expression
2999 return StringConcat.Create (ec, b.left, b.right, b.loc);
3003 sealed class PredefinedEqualityOperator : PredefinedOperator
3005 MethodSpec equal_method, inequal_method;
3007 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3008 : base (arg, arg, Operator.EqualityMask, retType)
3012 public override Expression ConvertResult (ResolveContext ec, Binary b)
3014 b.type = ReturnType;
3016 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3017 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3019 Arguments args = new Arguments (2);
3020 args.Add (new Argument (b.left));
3021 args.Add (new Argument (b.right));
3024 if (b.oper == Operator.Equality) {
3025 if (equal_method == null) {
3026 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3027 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3028 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3029 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3031 throw new NotImplementedException (left.GetSignatureForError ());
3034 method = equal_method;
3036 if (inequal_method == null) {
3037 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3038 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3039 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3040 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3042 throw new NotImplementedException (left.GetSignatureForError ());
3045 method = inequal_method;
3048 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3052 class PredefinedPointerOperator : PredefinedOperator
3054 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3055 : base (ltype, rtype, op_mask)
3059 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3060 : base (ltype, rtype, op_mask, retType)
3064 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3065 : base (type, op_mask, return_type)
3069 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3072 if (!lexpr.Type.IsPointer)
3075 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3079 if (right == null) {
3080 if (!rexpr.Type.IsPointer)
3083 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3090 public override Expression ConvertResult (ResolveContext ec, Binary b)
3093 b.left = EmptyCast.Create (b.left, left);
3094 } else if (right != null) {
3095 b.right = EmptyCast.Create (b.right, right);
3098 TypeSpec r_type = ReturnType;
3099 Expression left_arg, right_arg;
3100 if (r_type == null) {
3103 right_arg = b.right;
3104 r_type = b.left.Type;
3108 r_type = b.right.Type;
3112 right_arg = b.right;
3115 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3120 public enum Operator {
3121 Multiply = 0 | ArithmeticMask,
3122 Division = 1 | ArithmeticMask,
3123 Modulus = 2 | ArithmeticMask,
3124 Addition = 3 | ArithmeticMask | AdditionMask,
3125 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3127 LeftShift = 5 | ShiftMask,
3128 RightShift = 6 | ShiftMask,
3130 LessThan = 7 | ComparisonMask | RelationalMask,
3131 GreaterThan = 8 | ComparisonMask | RelationalMask,
3132 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3133 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3134 Equality = 11 | ComparisonMask | EqualityMask,
3135 Inequality = 12 | ComparisonMask | EqualityMask,
3137 BitwiseAnd = 13 | BitwiseMask,
3138 ExclusiveOr = 14 | BitwiseMask,
3139 BitwiseOr = 15 | BitwiseMask,
3141 LogicalAnd = 16 | LogicalMask,
3142 LogicalOr = 17 | LogicalMask,
3147 ValuesOnlyMask = ArithmeticMask - 1,
3148 ArithmeticMask = 1 << 5,
3150 ComparisonMask = 1 << 7,
3151 EqualityMask = 1 << 8,
3152 BitwiseMask = 1 << 9,
3153 LogicalMask = 1 << 10,
3154 AdditionMask = 1 << 11,
3155 SubtractionMask = 1 << 12,
3156 RelationalMask = 1 << 13,
3158 DecomposedMask = 1 << 19,
3159 NullableMask = 1 << 20,
3169 readonly Operator oper;
3170 Expression left, right;
3172 ConvCast.Mode enum_conversion;
3174 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3175 : this (oper, left, right)
3178 state |= State.Compound;
3181 public Binary (Operator oper, Expression left, Expression right)
3182 : this (oper, left, right, left.Location)
3186 public Binary (Operator oper, Expression left, Expression right, Location loc)
3196 public bool IsCompound {
3198 return (state & State.Compound) != 0;
3202 public Operator Oper {
3208 public Expression Left {
3214 public Expression Right {
3220 public override Location StartLocation {
3222 return left.StartLocation;
3229 /// Returns a stringified representation of the Operator
3231 string OperName (Operator oper)
3235 case Operator.Multiply:
3238 case Operator.Division:
3241 case Operator.Modulus:
3244 case Operator.Addition:
3247 case Operator.Subtraction:
3250 case Operator.LeftShift:
3253 case Operator.RightShift:
3256 case Operator.LessThan:
3259 case Operator.GreaterThan:
3262 case Operator.LessThanOrEqual:
3265 case Operator.GreaterThanOrEqual:
3268 case Operator.Equality:
3271 case Operator.Inequality:
3274 case Operator.BitwiseAnd:
3277 case Operator.BitwiseOr:
3280 case Operator.ExclusiveOr:
3283 case Operator.LogicalOr:
3286 case Operator.LogicalAnd:
3290 s = oper.ToString ();
3300 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3302 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3305 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3307 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3311 l = left.Type.GetSignatureForError ();
3312 r = right.Type.GetSignatureForError ();
3314 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3318 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3320 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3323 public override void FlowAnalysis (FlowAnalysisContext fc)
3326 // Optimized version when on-true/on-false data are not needed
3328 if ((oper & Operator.LogicalMask) == 0) {
3329 left.FlowAnalysis (fc);
3330 right.FlowAnalysis (fc);
3334 left.FlowAnalysisConditional (fc);
3335 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3336 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3338 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3339 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3340 right.FlowAnalysisConditional (fc);
3342 if (oper == Operator.LogicalOr)
3343 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3345 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3348 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3350 if ((oper & Operator.LogicalMask) == 0) {
3351 base.FlowAnalysisConditional (fc);
3355 left.FlowAnalysisConditional (fc);
3356 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3357 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3359 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3360 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3361 right.FlowAnalysisConditional (fc);
3363 var lc = left as Constant;
3364 if (oper == Operator.LogicalOr) {
3365 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3366 if (lc != null && lc.IsDefaultValue)
3367 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3369 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3371 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3372 if (lc != null && !lc.IsDefaultValue)
3373 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3375 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3380 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3382 string GetOperatorExpressionTypeName ()
3385 case Operator.Addition:
3386 return IsCompound ? "AddAssign" : "Add";
3387 case Operator.BitwiseAnd:
3388 return IsCompound ? "AndAssign" : "And";
3389 case Operator.BitwiseOr:
3390 return IsCompound ? "OrAssign" : "Or";
3391 case Operator.Division:
3392 return IsCompound ? "DivideAssign" : "Divide";
3393 case Operator.ExclusiveOr:
3394 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3395 case Operator.Equality:
3397 case Operator.GreaterThan:
3398 return "GreaterThan";
3399 case Operator.GreaterThanOrEqual:
3400 return "GreaterThanOrEqual";
3401 case Operator.Inequality:
3403 case Operator.LeftShift:
3404 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3405 case Operator.LessThan:
3407 case Operator.LessThanOrEqual:
3408 return "LessThanOrEqual";
3409 case Operator.LogicalAnd:
3411 case Operator.LogicalOr:
3413 case Operator.Modulus:
3414 return IsCompound ? "ModuloAssign" : "Modulo";
3415 case Operator.Multiply:
3416 return IsCompound ? "MultiplyAssign" : "Multiply";
3417 case Operator.RightShift:
3418 return IsCompound ? "RightShiftAssign" : "RightShift";
3419 case Operator.Subtraction:
3420 return IsCompound ? "SubtractAssign" : "Subtract";
3422 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3426 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3429 case Operator.Addition:
3430 return CSharp.Operator.OpType.Addition;
3431 case Operator.BitwiseAnd:
3432 case Operator.LogicalAnd:
3433 return CSharp.Operator.OpType.BitwiseAnd;
3434 case Operator.BitwiseOr:
3435 case Operator.LogicalOr:
3436 return CSharp.Operator.OpType.BitwiseOr;
3437 case Operator.Division:
3438 return CSharp.Operator.OpType.Division;
3439 case Operator.Equality:
3440 return CSharp.Operator.OpType.Equality;
3441 case Operator.ExclusiveOr:
3442 return CSharp.Operator.OpType.ExclusiveOr;
3443 case Operator.GreaterThan:
3444 return CSharp.Operator.OpType.GreaterThan;
3445 case Operator.GreaterThanOrEqual:
3446 return CSharp.Operator.OpType.GreaterThanOrEqual;
3447 case Operator.Inequality:
3448 return CSharp.Operator.OpType.Inequality;
3449 case Operator.LeftShift:
3450 return CSharp.Operator.OpType.LeftShift;
3451 case Operator.LessThan:
3452 return CSharp.Operator.OpType.LessThan;
3453 case Operator.LessThanOrEqual:
3454 return CSharp.Operator.OpType.LessThanOrEqual;
3455 case Operator.Modulus:
3456 return CSharp.Operator.OpType.Modulus;
3457 case Operator.Multiply:
3458 return CSharp.Operator.OpType.Multiply;
3459 case Operator.RightShift:
3460 return CSharp.Operator.OpType.RightShift;
3461 case Operator.Subtraction:
3462 return CSharp.Operator.OpType.Subtraction;
3464 throw new InternalErrorException (op.ToString ());
3468 public override bool ContainsEmitWithAwait ()
3470 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3473 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3478 case Operator.Multiply:
3479 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3480 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3481 opcode = OpCodes.Mul_Ovf;
3482 else if (!IsFloat (l))
3483 opcode = OpCodes.Mul_Ovf_Un;
3485 opcode = OpCodes.Mul;
3487 opcode = OpCodes.Mul;
3491 case Operator.Division:
3493 opcode = OpCodes.Div_Un;
3495 opcode = OpCodes.Div;
3498 case Operator.Modulus:
3500 opcode = OpCodes.Rem_Un;
3502 opcode = OpCodes.Rem;
3505 case Operator.Addition:
3506 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3507 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3508 opcode = OpCodes.Add_Ovf;
3509 else if (!IsFloat (l))
3510 opcode = OpCodes.Add_Ovf_Un;
3512 opcode = OpCodes.Add;
3514 opcode = OpCodes.Add;
3517 case Operator.Subtraction:
3518 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3519 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3520 opcode = OpCodes.Sub_Ovf;
3521 else if (!IsFloat (l))
3522 opcode = OpCodes.Sub_Ovf_Un;
3524 opcode = OpCodes.Sub;
3526 opcode = OpCodes.Sub;
3529 case Operator.RightShift:
3530 if (!(right is IntConstant)) {
3531 ec.EmitInt (GetShiftMask (l));
3532 ec.Emit (OpCodes.And);
3536 opcode = OpCodes.Shr_Un;
3538 opcode = OpCodes.Shr;
3541 case Operator.LeftShift:
3542 if (!(right is IntConstant)) {
3543 ec.EmitInt (GetShiftMask (l));
3544 ec.Emit (OpCodes.And);
3547 opcode = OpCodes.Shl;
3550 case Operator.Equality:
3551 opcode = OpCodes.Ceq;
3554 case Operator.Inequality:
3555 ec.Emit (OpCodes.Ceq);
3558 opcode = OpCodes.Ceq;
3561 case Operator.LessThan:
3563 opcode = OpCodes.Clt_Un;
3565 opcode = OpCodes.Clt;
3568 case Operator.GreaterThan:
3570 opcode = OpCodes.Cgt_Un;
3572 opcode = OpCodes.Cgt;
3575 case Operator.LessThanOrEqual:
3576 if (IsUnsigned (l) || IsFloat (l))
3577 ec.Emit (OpCodes.Cgt_Un);
3579 ec.Emit (OpCodes.Cgt);
3582 opcode = OpCodes.Ceq;
3585 case Operator.GreaterThanOrEqual:
3586 if (IsUnsigned (l) || IsFloat (l))
3587 ec.Emit (OpCodes.Clt_Un);
3589 ec.Emit (OpCodes.Clt);
3593 opcode = OpCodes.Ceq;
3596 case Operator.BitwiseOr:
3597 opcode = OpCodes.Or;
3600 case Operator.BitwiseAnd:
3601 opcode = OpCodes.And;
3604 case Operator.ExclusiveOr:
3605 opcode = OpCodes.Xor;
3609 throw new InternalErrorException (oper.ToString ());
3615 static int GetShiftMask (TypeSpec type)
3617 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3620 static bool IsUnsigned (TypeSpec t)
3622 switch (t.BuiltinType) {
3623 case BuiltinTypeSpec.Type.Char:
3624 case BuiltinTypeSpec.Type.UInt:
3625 case BuiltinTypeSpec.Type.ULong:
3626 case BuiltinTypeSpec.Type.UShort:
3627 case BuiltinTypeSpec.Type.Byte:
3634 static bool IsFloat (TypeSpec t)
3636 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3639 public Expression ResolveOperator (ResolveContext rc)
3641 eclass = ExprClass.Value;
3643 TypeSpec l = left.Type;
3644 TypeSpec r = right.Type;
3646 bool primitives_only = false;
3649 // Handles predefined primitive types
3651 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3652 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3653 if ((oper & Operator.ShiftMask) == 0) {
3654 if (!DoBinaryOperatorPromotion (rc))
3657 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3661 if (l.IsPointer || r.IsPointer)
3662 return ResolveOperatorPointer (rc, l, r);
3665 expr = ResolveUserOperator (rc, left, right);
3670 bool lenum = l.IsEnum;
3671 bool renum = r.IsEnum;
3672 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3676 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3677 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3682 if ((oper & Operator.BitwiseMask) != 0) {
3683 expr = EmptyCast.Create (expr, type);
3684 enum_conversion = GetEnumResultCast (type);
3686 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3687 expr = OptimizeAndOperation (expr);
3691 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3692 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3695 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3696 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3700 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3703 // We cannot break here there is also Enum + String possible match
3704 // which is not ambiguous with predefined enum operators
3707 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3708 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3712 } else if (l.IsDelegate || r.IsDelegate) {
3716 expr = ResolveOperatorDelegate (rc, l, r);
3718 // TODO: Can this be ambiguous
3726 // Equality operators are more complicated
3728 if ((oper & Operator.EqualityMask) != 0) {
3729 return ResolveEquality (rc, l, r, primitives_only);
3732 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3736 if (primitives_only)
3740 // Lifted operators have lower priority
3742 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3745 static bool IsEnumOrNullableEnum (TypeSpec type)
3747 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3751 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3752 // if 'left' is not an enumeration constant, create one from the type of 'right'
3753 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3756 case Operator.BitwiseOr:
3757 case Operator.BitwiseAnd:
3758 case Operator.ExclusiveOr:
3759 case Operator.Equality:
3760 case Operator.Inequality:
3761 case Operator.LessThan:
3762 case Operator.LessThanOrEqual:
3763 case Operator.GreaterThan:
3764 case Operator.GreaterThanOrEqual:
3765 if (left.Type.IsEnum)
3768 if (left.IsZeroInteger)
3769 return left.Reduce (ec, right.Type);
3773 case Operator.Addition:
3774 case Operator.Subtraction:
3777 case Operator.Multiply:
3778 case Operator.Division:
3779 case Operator.Modulus:
3780 case Operator.LeftShift:
3781 case Operator.RightShift:
3782 if (right.Type.IsEnum || left.Type.IsEnum)
3791 // The `|' operator used on types which were extended is dangerous
3793 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3795 OpcodeCast lcast = left as OpcodeCast;
3796 if (lcast != null) {
3797 if (IsUnsigned (lcast.UnderlyingType))
3801 OpcodeCast rcast = right as OpcodeCast;
3802 if (rcast != null) {
3803 if (IsUnsigned (rcast.UnderlyingType))
3807 if (lcast == null && rcast == null)
3810 // FIXME: consider constants
3812 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3813 ec.Report.Warning (675, 3, loc,
3814 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3815 ltype.GetSignatureForError ());
3818 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3820 return new PredefinedOperator[] {
3822 // Pointer arithmetic:
3824 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3825 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3826 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3827 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3829 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3830 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3831 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3832 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3835 // T* operator + (int y, T* x);
3836 // T* operator + (uint y, T *x);
3837 // T* operator + (long y, T *x);
3838 // T* operator + (ulong y, T *x);
3840 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3841 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3842 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3843 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3846 // long operator - (T* x, T *y)
3848 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3852 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3854 TypeSpec bool_type = types.Bool;
3857 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3858 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3859 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3860 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3861 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3862 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3863 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3865 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3866 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3867 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3868 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3869 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3870 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3871 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3873 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3874 // Remaining string operators are in lifted tables
3876 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3878 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3879 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3880 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3884 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3886 var types = module.Compiler.BuiltinTypes;
3889 // Not strictly lifted but need to be in second group otherwise expressions like
3890 // int + null would resolve to +(object, string) instead of +(int?, int?)
3892 var string_operators = new [] {
3893 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3894 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3897 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3898 if (nullable == null)
3899 return string_operators;
3901 var bool_type = types.Bool;
3903 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3904 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3905 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3906 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3907 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3908 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3909 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3910 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3913 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3914 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3915 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3916 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3917 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3918 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3919 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3921 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3922 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3923 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3924 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3925 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3926 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3927 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3929 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3931 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3932 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3933 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3935 string_operators [0],
3936 string_operators [1]
3940 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3942 TypeSpec bool_type = types.Bool;
3945 new PredefinedEqualityOperator (types.String, bool_type),
3946 new PredefinedEqualityOperator (types.Delegate, bool_type),
3947 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3948 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3949 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3950 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3951 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3952 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3953 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3954 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3958 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3960 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3962 if (nullable == null)
3963 return new PredefinedOperator [0];
3965 var types = module.Compiler.BuiltinTypes;
3966 var bool_type = types.Bool;
3967 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3968 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3969 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3970 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3971 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3972 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3973 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3974 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3977 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3978 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3979 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3980 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3981 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3982 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3983 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3984 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3989 // 7.2.6.2 Binary numeric promotions
3991 bool DoBinaryOperatorPromotion (ResolveContext rc)
3993 TypeSpec ltype = left.Type;
3994 if (ltype.IsNullableType) {
3995 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3999 // This is numeric promotion code only
4001 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4004 TypeSpec rtype = right.Type;
4005 if (rtype.IsNullableType) {
4006 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4009 var lb = ltype.BuiltinType;
4010 var rb = rtype.BuiltinType;
4014 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4015 type = rc.BuiltinTypes.Decimal;
4016 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4017 type = rc.BuiltinTypes.Double;
4018 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4019 type = rc.BuiltinTypes.Float;
4020 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4021 type = rc.BuiltinTypes.ULong;
4023 if (IsSignedType (lb)) {
4024 expr = ConvertSignedConstant (left, type);
4028 } else if (IsSignedType (rb)) {
4029 expr = ConvertSignedConstant (right, type);
4035 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4036 type = rc.BuiltinTypes.Long;
4037 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4038 type = rc.BuiltinTypes.UInt;
4040 if (IsSignedType (lb)) {
4041 expr = ConvertSignedConstant (left, type);
4043 type = rc.BuiltinTypes.Long;
4044 } else if (IsSignedType (rb)) {
4045 expr = ConvertSignedConstant (right, type);
4047 type = rc.BuiltinTypes.Long;
4050 type = rc.BuiltinTypes.Int;
4053 if (ltype != type) {
4054 expr = PromoteExpression (rc, left, type);
4061 if (rtype != type) {
4062 expr = PromoteExpression (rc, right, type);
4072 static bool IsSignedType (BuiltinTypeSpec.Type type)
4075 case BuiltinTypeSpec.Type.Int:
4076 case BuiltinTypeSpec.Type.Short:
4077 case BuiltinTypeSpec.Type.SByte:
4078 case BuiltinTypeSpec.Type.Long:
4085 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4087 var c = expr as Constant;
4091 return c.ConvertImplicitly (type);
4094 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4096 if (expr.Type.IsNullableType) {
4097 return Convert.ImplicitConversionStandard (rc, expr,
4098 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4101 var c = expr as Constant;
4103 return c.ConvertImplicitly (type);
4105 return Convert.ImplicitNumericConversion (expr, type);
4108 protected override Expression DoResolve (ResolveContext ec)
4113 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4114 left = ((ParenthesizedExpression) left).Expr;
4115 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4119 if (left.eclass == ExprClass.Type) {
4120 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4124 left = left.Resolve (ec);
4129 right = right.Resolve (ec);
4133 Constant lc = left as Constant;
4134 Constant rc = right as Constant;
4136 // The conversion rules are ignored in enum context but why
4137 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4138 lc = EnumLiftUp (ec, lc, rc);
4140 rc = EnumLiftUp (ec, rc, lc);
4143 if (rc != null && lc != null) {
4144 int prev_e = ec.Report.Errors;
4145 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4146 if (e != null || ec.Report.Errors != prev_e)
4150 // Comparison warnings
4151 if ((oper & Operator.ComparisonMask) != 0) {
4152 if (left.Equals (right)) {
4153 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4155 CheckOutOfRangeComparison (ec, lc, right.Type);
4156 CheckOutOfRangeComparison (ec, rc, left.Type);
4159 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4160 return DoResolveDynamic (ec);
4162 return DoResolveCore (ec, left, right);
4165 Expression DoResolveDynamic (ResolveContext rc)
4168 var rt = right.Type;
4169 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4170 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4171 Error_OperatorCannotBeApplied (rc, left, right);
4178 // Special handling for logical boolean operators which require rhs not to be
4179 // evaluated based on lhs value
4181 if ((oper & Operator.LogicalMask) != 0) {
4182 Expression cond_left, cond_right, expr;
4184 args = new Arguments (2);
4186 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4187 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4189 var cond_args = new Arguments (1);
4190 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4193 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4194 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4196 left = temp.CreateReferenceExpression (rc, loc);
4197 if (oper == Operator.LogicalAnd) {
4198 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4201 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4205 args.Add (new Argument (left));
4206 args.Add (new Argument (right));
4207 cond_right = new DynamicExpressionStatement (this, args, loc);
4209 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4211 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4212 rc.Report.Error (7083, left.Location,
4213 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4214 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4218 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4219 args.Add (new Argument (right));
4220 right = new DynamicExpressionStatement (this, args, loc);
4223 // bool && dynamic => (temp = left) ? temp && right : temp;
4224 // bool || dynamic => (temp = left) ? temp : temp || right;
4226 if (oper == Operator.LogicalAnd) {
4228 cond_right = temp.CreateReferenceExpression (rc, loc);
4230 cond_left = temp.CreateReferenceExpression (rc, loc);
4234 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4237 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4240 args = new Arguments (2);
4241 args.Add (new Argument (left));
4242 args.Add (new Argument (right));
4243 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4246 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4248 Expression expr = ResolveOperator (ec);
4250 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4252 if (left == null || right == null)
4253 throw new InternalErrorException ("Invalid conversion");
4255 if (oper == Operator.BitwiseOr)
4256 CheckBitwiseOrOnSignExtended (ec);
4261 public override SLE.Expression MakeExpression (BuilderContext ctx)
4263 return MakeExpression (ctx, left, right);
4266 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4268 var le = left.MakeExpression (ctx);
4269 var re = right.MakeExpression (ctx);
4270 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4273 case Operator.Addition:
4274 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4275 case Operator.BitwiseAnd:
4276 return SLE.Expression.And (le, re);
4277 case Operator.BitwiseOr:
4278 return SLE.Expression.Or (le, re);
4279 case Operator.Division:
4280 return SLE.Expression.Divide (le, re);
4281 case Operator.Equality:
4282 return SLE.Expression.Equal (le, re);
4283 case Operator.ExclusiveOr:
4284 return SLE.Expression.ExclusiveOr (le, re);
4285 case Operator.GreaterThan:
4286 return SLE.Expression.GreaterThan (le, re);
4287 case Operator.GreaterThanOrEqual:
4288 return SLE.Expression.GreaterThanOrEqual (le, re);
4289 case Operator.Inequality:
4290 return SLE.Expression.NotEqual (le, re);
4291 case Operator.LeftShift:
4292 return SLE.Expression.LeftShift (le, re);
4293 case Operator.LessThan:
4294 return SLE.Expression.LessThan (le, re);
4295 case Operator.LessThanOrEqual:
4296 return SLE.Expression.LessThanOrEqual (le, re);
4297 case Operator.LogicalAnd:
4298 return SLE.Expression.AndAlso (le, re);
4299 case Operator.LogicalOr:
4300 return SLE.Expression.OrElse (le, re);
4301 case Operator.Modulus:
4302 return SLE.Expression.Modulo (le, re);
4303 case Operator.Multiply:
4304 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4305 case Operator.RightShift:
4306 return SLE.Expression.RightShift (le, re);
4307 case Operator.Subtraction:
4308 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4310 throw new NotImplementedException (oper.ToString ());
4315 // D operator + (D x, D y)
4316 // D operator - (D x, D y)
4318 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4320 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4322 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4323 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4328 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4329 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4339 MethodSpec method = null;
4340 Arguments args = new Arguments (2);
4341 args.Add (new Argument (left));
4342 args.Add (new Argument (right));
4344 if (oper == Operator.Addition) {
4345 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4346 } else if (oper == Operator.Subtraction) {
4347 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4351 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4353 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4354 return new ClassCast (expr, l);
4358 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4360 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4363 // bool operator == (E x, E y);
4364 // bool operator != (E x, E y);
4365 // bool operator < (E x, E y);
4366 // bool operator > (E x, E y);
4367 // bool operator <= (E x, E y);
4368 // bool operator >= (E x, E y);
4370 // E operator & (E x, E y);
4371 // E operator | (E x, E y);
4372 // E operator ^ (E x, E y);
4375 if ((oper & Operator.ComparisonMask) != 0) {
4376 type = rc.BuiltinTypes.Bool;
4382 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4388 if (ltype == rtype) {
4392 var lifted = new Nullable.LiftedBinaryOperator (this);
4394 lifted.Right = right;
4395 return lifted.Resolve (rc);
4398 if (renum && !ltype.IsNullableType) {
4399 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4404 } else if (lenum && !rtype.IsNullableType) {
4405 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4413 // Now try lifted version of predefined operator
4415 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4416 if (nullable_type != null) {
4417 if (renum && !ltype.IsNullableType) {
4418 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4420 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4423 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4426 if ((oper & Operator.BitwiseMask) != 0)
4430 if ((oper & Operator.BitwiseMask) != 0)
4431 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4433 return CreateLiftedValueTypeResult (rc, rtype);
4437 var lifted = new Nullable.LiftedBinaryOperator (this);
4439 lifted.Right = right;
4440 return lifted.Resolve (rc);
4442 } else if (lenum && !rtype.IsNullableType) {
4443 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4445 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4448 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4451 if ((oper & Operator.BitwiseMask) != 0)
4455 if ((oper & Operator.BitwiseMask) != 0)
4456 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4458 return CreateLiftedValueTypeResult (rc, ltype);
4462 var lifted = new Nullable.LiftedBinaryOperator (this);
4464 lifted.Right = expr;
4465 return lifted.Resolve (rc);
4467 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4468 Nullable.Unwrap unwrap = null;
4469 if (left.IsNull || right.IsNull) {
4470 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4471 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4473 if ((oper & Operator.RelationalMask) != 0)
4474 return CreateLiftedValueTypeResult (rc, rtype);
4476 if ((oper & Operator.BitwiseMask) != 0)
4477 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4480 return CreateLiftedValueTypeResult (rc, left.Type);
4482 // Equality operators are valid between E? and null
4484 unwrap = new Nullable.Unwrap (right);
4486 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4492 var lifted = new Nullable.LiftedBinaryOperator (this);
4494 lifted.Right = right;
4495 lifted.UnwrapRight = unwrap;
4496 return lifted.Resolve (rc);
4498 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4499 Nullable.Unwrap unwrap = null;
4500 if (right.IsNull || left.IsNull) {
4501 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4502 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4504 if ((oper & Operator.RelationalMask) != 0)
4505 return CreateLiftedValueTypeResult (rc, ltype);
4507 if ((oper & Operator.BitwiseMask) != 0)
4508 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4511 return CreateLiftedValueTypeResult (rc, right.Type);
4513 // Equality operators are valid between E? and null
4515 unwrap = new Nullable.Unwrap (left);
4517 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4523 var lifted = new Nullable.LiftedBinaryOperator (this);
4525 lifted.UnwrapLeft = unwrap;
4526 lifted.Right = expr;
4527 return lifted.Resolve (rc);
4535 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4537 TypeSpec underlying_type;
4538 if (expr.Type.IsNullableType) {
4539 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4541 underlying_type = EnumSpec.GetUnderlyingType (nt);
4543 underlying_type = nt;
4544 } else if (expr.Type.IsEnum) {
4545 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4547 underlying_type = expr.Type;
4550 switch (underlying_type.BuiltinType) {
4551 case BuiltinTypeSpec.Type.SByte:
4552 case BuiltinTypeSpec.Type.Byte:
4553 case BuiltinTypeSpec.Type.Short:
4554 case BuiltinTypeSpec.Type.UShort:
4555 underlying_type = rc.BuiltinTypes.Int;
4559 if (expr.Type.IsNullableType || liftType)
4560 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4562 if (expr.Type == underlying_type)
4565 return EmptyCast.Create (expr, underlying_type);
4568 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4571 // U operator - (E e, E f)
4572 // E operator - (E e, U x) // Internal decomposition operator
4573 // E operator - (U x, E e) // Internal decomposition operator
4575 // E operator + (E e, U x)
4576 // E operator + (U x, E e)
4585 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4591 if (!enum_type.IsNullableType) {
4592 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4594 if (oper == Operator.Subtraction)
4595 expr = ConvertEnumSubtractionResult (rc, expr);
4597 expr = ConvertEnumAdditionalResult (expr, enum_type);
4599 enum_conversion = GetEnumResultCast (expr.Type);
4604 var nullable = rc.Module.PredefinedTypes.Nullable;
4607 // Don't try nullable version when nullable type is undefined
4609 if (!nullable.IsDefined)
4612 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4615 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4617 if (oper == Operator.Subtraction)
4618 expr = ConvertEnumSubtractionResult (rc, expr);
4620 expr = ConvertEnumAdditionalResult (expr, enum_type);
4622 enum_conversion = GetEnumResultCast (expr.Type);
4628 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4630 return EmptyCast.Create (expr, enumType);
4633 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4636 // Enumeration subtraction has different result type based on
4639 TypeSpec result_type;
4640 if (left.Type == right.Type) {
4641 var c = right as EnumConstant;
4642 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4644 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4645 // E which is not what expressions E - 1 or 0 - E return
4647 result_type = left.Type;
4649 result_type = left.Type.IsNullableType ?
4650 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4651 EnumSpec.GetUnderlyingType (left.Type);
4654 if (IsEnumOrNullableEnum (left.Type)) {
4655 result_type = left.Type;
4657 result_type = right.Type;
4660 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4661 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4664 return EmptyCast.Create (expr, result_type);
4667 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4669 if (type.IsNullableType)
4670 type = Nullable.NullableInfo.GetUnderlyingType (type);
4673 type = EnumSpec.GetUnderlyingType (type);
4675 switch (type.BuiltinType) {
4676 case BuiltinTypeSpec.Type.SByte:
4677 return ConvCast.Mode.I4_I1;
4678 case BuiltinTypeSpec.Type.Byte:
4679 return ConvCast.Mode.I4_U1;
4680 case BuiltinTypeSpec.Type.Short:
4681 return ConvCast.Mode.I4_I2;
4682 case BuiltinTypeSpec.Type.UShort:
4683 return ConvCast.Mode.I4_U2;
4690 // Equality operators rules
4692 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4695 type = ec.BuiltinTypes.Bool;
4696 bool no_arg_conv = false;
4698 if (!primitives_only) {
4701 // a, Both operands are reference-type values or the value null
4702 // b, One operand is a value of type T where T is a type-parameter and
4703 // the other operand is the value null. Furthermore T does not have the
4704 // value type constraint
4706 // LAMESPEC: Very confusing details in the specification, basically any
4707 // reference like type-parameter is allowed
4709 var tparam_l = l as TypeParameterSpec;
4710 var tparam_r = r as TypeParameterSpec;
4711 if (tparam_l != null) {
4712 if (right is NullLiteral) {
4713 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4716 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4720 if (!tparam_l.IsReferenceType)
4723 l = tparam_l.GetEffectiveBase ();
4724 left = new BoxedCast (left, l);
4725 } else if (left is NullLiteral && tparam_r == null) {
4726 if (TypeSpec.IsReferenceType (r))
4729 if (r.Kind == MemberKind.InternalCompilerType)
4733 if (tparam_r != null) {
4734 if (left is NullLiteral) {
4735 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4738 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4742 if (!tparam_r.IsReferenceType)
4745 r = tparam_r.GetEffectiveBase ();
4746 right = new BoxedCast (right, r);
4747 } else if (right is NullLiteral) {
4748 if (TypeSpec.IsReferenceType (l))
4751 if (l.Kind == MemberKind.InternalCompilerType)
4756 // LAMESPEC: method groups can be compared when they convert to other side delegate
4759 if (right.eclass == ExprClass.MethodGroup) {
4760 result = Convert.ImplicitConversion (ec, right, l, loc);
4766 } else if (r.IsDelegate && l != r) {
4769 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4770 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4777 no_arg_conv = l == r && !l.IsStruct;
4782 // bool operator != (string a, string b)
4783 // bool operator == (string a, string b)
4785 // bool operator != (Delegate a, Delegate b)
4786 // bool operator == (Delegate a, Delegate b)
4788 // bool operator != (bool a, bool b)
4789 // bool operator == (bool a, bool b)
4791 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4792 // they implement an implicit conversion to any of types above. This does
4793 // not apply when both operands are of same reference type
4795 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4796 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4801 // Now try lifted version of predefined operators
4803 if (no_arg_conv && !l.IsNullableType) {
4805 // Optimizes cases which won't match
4808 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4814 // The == and != operators permit one operand to be a value of a nullable
4815 // type and the other to be the null literal, even if no predefined or user-defined
4816 // operator (in unlifted or lifted form) exists for the operation.
4818 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4819 var lifted = new Nullable.LiftedBinaryOperator (this);
4821 lifted.Right = right;
4822 return lifted.Resolve (ec);
4827 // bool operator != (object a, object b)
4828 // bool operator == (object a, object b)
4830 // An explicit reference conversion exists from the
4831 // type of either operand to the type of the other operand.
4834 // Optimize common path
4836 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4839 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4840 !Convert.ExplicitReferenceConversionExists (r, l))
4843 // Reject allowed explicit conversions like int->object
4844 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4847 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4848 ec.Report.Warning (253, 2, loc,
4849 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4850 l.GetSignatureForError ());
4852 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4853 ec.Report.Warning (252, 2, loc,
4854 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4855 r.GetSignatureForError ());
4861 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4864 // bool operator == (void* x, void* y);
4865 // bool operator != (void* x, void* y);
4866 // bool operator < (void* x, void* y);
4867 // bool operator > (void* x, void* y);
4868 // bool operator <= (void* x, void* y);
4869 // bool operator >= (void* x, void* y);
4871 if ((oper & Operator.ComparisonMask) != 0) {
4874 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4881 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4887 type = ec.BuiltinTypes.Bool;
4891 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4895 // Build-in operators method overloading
4897 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4899 PredefinedOperator best_operator = null;
4900 TypeSpec l = left.Type;
4901 TypeSpec r = right.Type;
4902 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4904 foreach (PredefinedOperator po in operators) {
4905 if ((po.OperatorsMask & oper_mask) == 0)
4908 if (primitives_only) {
4909 if (!po.IsPrimitiveApplicable (l, r))
4912 if (!po.IsApplicable (ec, left, right))
4916 if (best_operator == null) {
4918 if (primitives_only)
4924 best_operator = po.ResolveBetterOperator (ec, best_operator);
4926 if (best_operator == null) {
4927 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4928 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4935 if (best_operator == null)
4938 return best_operator.ConvertResult (ec, this);
4942 // Optimize & constant expressions with 0 value
4944 Expression OptimizeAndOperation (Expression expr)
4946 Constant rc = right as Constant;
4947 Constant lc = left as Constant;
4948 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4950 // The result is a constant with side-effect
4952 Constant side_effect = rc == null ?
4953 new SideEffectConstant (lc, right, loc) :
4954 new SideEffectConstant (rc, left, loc);
4956 return ReducedExpression.Create (side_effect, expr);
4963 // Value types can be compared with the null literal because of the lifting
4964 // language rules. However the result is always true or false.
4966 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4968 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4969 type = rc.BuiltinTypes.Bool;
4973 // FIXME: Handle side effect constants
4974 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4976 if ((Oper & Operator.EqualityMask) != 0) {
4977 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4978 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4980 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4981 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4988 // Performs user-operator overloading
4990 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4992 Expression oper_expr;
4994 var op = ConvertBinaryToUserOperator (oper);
4996 if (l.IsNullableType)
4997 l = Nullable.NullableInfo.GetUnderlyingType (l);
4999 if (r.IsNullableType)
5000 r = Nullable.NullableInfo.GetUnderlyingType (r);
5002 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5003 IList<MemberSpec> right_operators = null;
5006 right_operators = MemberCache.GetUserOperator (r, op, false);
5007 if (right_operators == null && left_operators == null)
5009 } else if (left_operators == null) {
5013 Arguments args = new Arguments (2);
5014 Argument larg = new Argument (left);
5016 Argument rarg = new Argument (right);
5020 // User-defined operator implementations always take precedence
5021 // over predefined operator implementations
5023 if (left_operators != null && right_operators != null) {
5024 left_operators = CombineUserOperators (left_operators, right_operators);
5025 } else if (right_operators != null) {
5026 left_operators = right_operators;
5029 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5030 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5032 var res = new OverloadResolver (left_operators, restr, loc);
5034 var oper_method = res.ResolveOperator (rc, ref args);
5035 if (oper_method == null) {
5037 // Logical && and || cannot be lifted
5039 if ((oper & Operator.LogicalMask) != 0)
5043 // Apply lifted user operators only for liftable types. Implicit conversion
5044 // to nullable types is not allowed
5046 if (!IsLiftedOperatorApplicable ())
5049 // TODO: Cache the result in module container
5050 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5051 if (lifted_methods == null)
5054 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5056 oper_method = res.ResolveOperator (rc, ref args);
5057 if (oper_method == null)
5060 MethodSpec best_original = null;
5061 foreach (MethodSpec ms in left_operators) {
5062 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5068 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5070 // Expression trees use lifted notation in this case
5072 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5073 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5076 var ptypes = best_original.Parameters.Types;
5078 if (left.IsNull || right.IsNull) {
5080 // The lifted operator produces a null value if one or both operands are null
5082 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5083 type = oper_method.ReturnType;
5084 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5088 // The lifted operator produces the value false if one or both operands are null for
5089 // relational operators.
5091 if ((oper & Operator.RelationalMask) != 0) {
5093 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5094 // because return type is actually bool
5096 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5099 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5100 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5104 type = oper_method.ReturnType;
5105 var lifted = new Nullable.LiftedBinaryOperator (this);
5106 lifted.UserOperator = best_original;
5108 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5109 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5112 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5113 lifted.UnwrapRight = new Nullable.Unwrap (right);
5116 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5117 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5119 return lifted.Resolve (rc);
5122 if ((oper & Operator.LogicalMask) != 0) {
5123 // TODO: CreateExpressionTree is allocated every time
5124 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5125 oper == Operator.LogicalAnd, loc).Resolve (rc);
5127 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5130 this.left = larg.Expr;
5131 this.right = rarg.Expr;
5136 bool IsLiftedOperatorApplicable ()
5138 if (left.Type.IsNullableType) {
5139 if ((oper & Operator.EqualityMask) != 0)
5140 return !right.IsNull;
5145 if (right.Type.IsNullableType) {
5146 if ((oper & Operator.EqualityMask) != 0)
5147 return !left.IsNull;
5152 if (TypeSpec.IsValueType (left.Type))
5153 return right.IsNull;
5155 if (TypeSpec.IsValueType (right.Type))
5161 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5163 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5164 if (nullable_type == null)
5168 // Lifted operators permit predefined and user-defined operators that operate
5169 // on non-nullable value types to also be used with nullable forms of those types.
5170 // Lifted operators are constructed from predefined and user-defined operators
5171 // that meet certain requirements
5173 List<MemberSpec> lifted = null;
5174 foreach (MethodSpec oper in operators) {
5176 if ((Oper & Operator.ComparisonMask) != 0) {
5178 // Result type must be of type bool for lifted comparison operators
5180 rt = oper.ReturnType;
5181 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5184 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5190 var ptypes = oper.Parameters.Types;
5191 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5195 // LAMESPEC: I am not sure why but for equality operators to be lifted
5196 // both types have to match
5198 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5202 lifted = new List<MemberSpec> ();
5205 // The lifted form is constructed by adding a single ? modifier to each operand and
5206 // result type except for comparison operators where return type is bool
5209 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5211 var parameters = ParametersCompiled.CreateFullyResolved (
5212 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5213 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5215 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5216 rt, parameters, oper.Modifiers);
5218 lifted.Add (lifted_op);
5225 // Merge two sets of user operators into one, they are mostly distinguish
5226 // except when they share base type and it contains an operator
5228 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5230 var combined = new List<MemberSpec> (left.Count + right.Count);
5231 combined.AddRange (left);
5232 foreach (var r in right) {
5234 foreach (var l in left) {
5235 if (l.DeclaringType == r.DeclaringType) {
5248 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5250 if (c is IntegralConstant || c is CharConstant) {
5252 c.ConvertExplicitly (true, type);
5253 } catch (OverflowException) {
5254 ec.Report.Warning (652, 2, loc,
5255 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5256 type.GetSignatureForError ());
5262 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5263 /// context of a conditional bool expression. This function will return
5264 /// false if it is was possible to use EmitBranchable, or true if it was.
5266 /// The expression's code is generated, and we will generate a branch to `target'
5267 /// if the resulting expression value is equal to isTrue
5269 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5271 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5272 left = left.EmitToField (ec);
5274 if ((oper & Operator.LogicalMask) == 0) {
5275 right = right.EmitToField (ec);
5280 // This is more complicated than it looks, but its just to avoid
5281 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5282 // but on top of that we want for == and != to use a special path
5283 // if we are comparing against null
5285 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5286 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5289 // put the constant on the rhs, for simplicity
5291 if (left is Constant) {
5292 Expression swap = right;
5298 // brtrue/brfalse works with native int only
5300 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5301 left.EmitBranchable (ec, target, my_on_true);
5304 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5305 // right is a boolean, and it's not 'false' => it is 'true'
5306 left.EmitBranchable (ec, target, !my_on_true);
5310 } else if (oper == Operator.LogicalAnd) {
5313 Label tests_end = ec.DefineLabel ();
5315 left.EmitBranchable (ec, tests_end, false);
5316 right.EmitBranchable (ec, target, true);
5317 ec.MarkLabel (tests_end);
5320 // This optimizes code like this
5321 // if (true && i > 4)
5323 if (!(left is Constant))
5324 left.EmitBranchable (ec, target, false);
5326 if (!(right is Constant))
5327 right.EmitBranchable (ec, target, false);
5332 } else if (oper == Operator.LogicalOr){
5334 left.EmitBranchable (ec, target, true);
5335 right.EmitBranchable (ec, target, true);
5338 Label tests_end = ec.DefineLabel ();
5339 left.EmitBranchable (ec, tests_end, true);
5340 right.EmitBranchable (ec, target, false);
5341 ec.MarkLabel (tests_end);
5346 } else if ((oper & Operator.ComparisonMask) == 0) {
5347 base.EmitBranchable (ec, target, on_true);
5354 TypeSpec t = left.Type;
5355 bool is_float = IsFloat (t);
5356 bool is_unsigned = is_float || IsUnsigned (t);
5359 case Operator.Equality:
5361 ec.Emit (OpCodes.Beq, target);
5363 ec.Emit (OpCodes.Bne_Un, target);
5366 case Operator.Inequality:
5368 ec.Emit (OpCodes.Bne_Un, target);
5370 ec.Emit (OpCodes.Beq, target);
5373 case Operator.LessThan:
5375 if (is_unsigned && !is_float)
5376 ec.Emit (OpCodes.Blt_Un, target);
5378 ec.Emit (OpCodes.Blt, target);
5381 ec.Emit (OpCodes.Bge_Un, target);
5383 ec.Emit (OpCodes.Bge, target);
5386 case Operator.GreaterThan:
5388 if (is_unsigned && !is_float)
5389 ec.Emit (OpCodes.Bgt_Un, target);
5391 ec.Emit (OpCodes.Bgt, target);
5394 ec.Emit (OpCodes.Ble_Un, target);
5396 ec.Emit (OpCodes.Ble, target);
5399 case Operator.LessThanOrEqual:
5401 if (is_unsigned && !is_float)
5402 ec.Emit (OpCodes.Ble_Un, target);
5404 ec.Emit (OpCodes.Ble, target);
5407 ec.Emit (OpCodes.Bgt_Un, target);
5409 ec.Emit (OpCodes.Bgt, target);
5413 case Operator.GreaterThanOrEqual:
5415 if (is_unsigned && !is_float)
5416 ec.Emit (OpCodes.Bge_Un, target);
5418 ec.Emit (OpCodes.Bge, target);
5421 ec.Emit (OpCodes.Blt_Un, target);
5423 ec.Emit (OpCodes.Blt, target);
5426 throw new InternalErrorException (oper.ToString ());
5430 public override void Emit (EmitContext ec)
5432 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5433 left = left.EmitToField (ec);
5435 if ((oper & Operator.LogicalMask) == 0) {
5436 right = right.EmitToField (ec);
5441 // Handle short-circuit operators differently
5444 if ((oper & Operator.LogicalMask) != 0) {
5445 Label load_result = ec.DefineLabel ();
5446 Label end = ec.DefineLabel ();
5448 bool is_or = oper == Operator.LogicalOr;
5449 left.EmitBranchable (ec, load_result, is_or);
5451 ec.Emit (OpCodes.Br_S, end);
5453 ec.MarkLabel (load_result);
5454 ec.EmitInt (is_or ? 1 : 0);
5460 // Optimize zero-based operations which cannot be optimized at expression level
5462 if (oper == Operator.Subtraction) {
5463 var lc = left as IntegralConstant;
5464 if (lc != null && lc.IsDefaultValue) {
5466 ec.Emit (OpCodes.Neg);
5471 EmitOperator (ec, left, right);
5474 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5479 EmitOperatorOpcode (ec, oper, left.Type, right);
5482 // Emit result enumerable conversion this way because it's quite complicated get it
5483 // to resolved tree because expression tree cannot see it.
5485 if (enum_conversion != 0)
5486 ConvCast.Emit (ec, enum_conversion);
5489 public override void EmitSideEffect (EmitContext ec)
5491 if ((oper & Operator.LogicalMask) != 0 ||
5492 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5493 base.EmitSideEffect (ec);
5495 left.EmitSideEffect (ec);
5496 right.EmitSideEffect (ec);
5500 public override Expression EmitToField (EmitContext ec)
5502 if ((oper & Operator.LogicalMask) == 0) {
5503 var await_expr = left as Await;
5504 if (await_expr != null && right.IsSideEffectFree) {
5505 await_expr.Statement.EmitPrologue (ec);
5506 left = await_expr.Statement.GetResultExpression (ec);
5510 await_expr = right as Await;
5511 if (await_expr != null && left.IsSideEffectFree) {
5512 await_expr.Statement.EmitPrologue (ec);
5513 right = await_expr.Statement.GetResultExpression (ec);
5518 return base.EmitToField (ec);
5521 protected override void CloneTo (CloneContext clonectx, Expression t)
5523 Binary target = (Binary) t;
5525 target.left = left.Clone (clonectx);
5526 target.right = right.Clone (clonectx);
5529 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5531 Arguments binder_args = new Arguments (4);
5533 MemberAccess sle = new MemberAccess (new MemberAccess (
5534 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5536 CSharpBinderFlags flags = 0;
5537 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5538 flags = CSharpBinderFlags.CheckedContext;
5540 if ((oper & Operator.LogicalMask) != 0)
5541 flags |= CSharpBinderFlags.BinaryOperationLogical;
5543 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5544 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5545 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5546 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5548 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5551 public override Expression CreateExpressionTree (ResolveContext ec)
5553 return CreateExpressionTree (ec, null);
5556 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5559 bool lift_arg = false;
5562 case Operator.Addition:
5563 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5564 method_name = "AddChecked";
5566 method_name = "Add";
5568 case Operator.BitwiseAnd:
5569 method_name = "And";
5571 case Operator.BitwiseOr:
5574 case Operator.Division:
5575 method_name = "Divide";
5577 case Operator.Equality:
5578 method_name = "Equal";
5581 case Operator.ExclusiveOr:
5582 method_name = "ExclusiveOr";
5584 case Operator.GreaterThan:
5585 method_name = "GreaterThan";
5588 case Operator.GreaterThanOrEqual:
5589 method_name = "GreaterThanOrEqual";
5592 case Operator.Inequality:
5593 method_name = "NotEqual";
5596 case Operator.LeftShift:
5597 method_name = "LeftShift";
5599 case Operator.LessThan:
5600 method_name = "LessThan";
5603 case Operator.LessThanOrEqual:
5604 method_name = "LessThanOrEqual";
5607 case Operator.LogicalAnd:
5608 method_name = "AndAlso";
5610 case Operator.LogicalOr:
5611 method_name = "OrElse";
5613 case Operator.Modulus:
5614 method_name = "Modulo";
5616 case Operator.Multiply:
5617 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5618 method_name = "MultiplyChecked";
5620 method_name = "Multiply";
5622 case Operator.RightShift:
5623 method_name = "RightShift";
5625 case Operator.Subtraction:
5626 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5627 method_name = "SubtractChecked";
5629 method_name = "Subtract";
5633 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5636 Arguments args = new Arguments (2);
5637 args.Add (new Argument (left.CreateExpressionTree (ec)));
5638 args.Add (new Argument (right.CreateExpressionTree (ec)));
5639 if (method != null) {
5641 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5643 args.Add (new Argument (method));
5646 return CreateExpressionFactoryCall (ec, method_name, args);
5649 public override object Accept (StructuralVisitor visitor)
5651 return visitor.Visit (this);
5657 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5658 // b, c, d... may be strings or objects.
5660 public class StringConcat : Expression
5662 Arguments arguments;
5664 StringConcat (Location loc)
5667 arguments = new Arguments (2);
5670 public override bool ContainsEmitWithAwait ()
5672 return arguments.ContainsEmitWithAwait ();
5675 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5677 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5678 throw new ArgumentException ();
5680 var s = new StringConcat (loc);
5681 s.type = rc.BuiltinTypes.String;
5682 s.eclass = ExprClass.Value;
5684 s.Append (rc, left);
5685 s.Append (rc, right);
5689 public override Expression CreateExpressionTree (ResolveContext ec)
5691 Argument arg = arguments [0];
5692 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5696 // Creates nested calls tree from an array of arguments used for IL emit
5698 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5700 Arguments concat_args = new Arguments (2);
5701 Arguments add_args = new Arguments (3);
5703 concat_args.Add (left);
5704 add_args.Add (new Argument (left_etree));
5706 concat_args.Add (arguments [pos]);
5707 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5709 var methods = GetConcatMethodCandidates ();
5710 if (methods == null)
5713 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5714 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5718 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5720 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5721 if (++pos == arguments.Count)
5724 left = new Argument (new EmptyExpression (method.ReturnType));
5725 return CreateExpressionAddCall (ec, left, expr, pos);
5728 protected override Expression DoResolve (ResolveContext ec)
5733 void Append (ResolveContext rc, Expression operand)
5738 StringConstant sc = operand as StringConstant;
5740 if (arguments.Count != 0) {
5741 Argument last_argument = arguments [arguments.Count - 1];
5742 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5743 if (last_expr_constant != null) {
5744 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5750 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5752 StringConcat concat_oper = operand as StringConcat;
5753 if (concat_oper != null) {
5754 arguments.AddRange (concat_oper.arguments);
5759 arguments.Add (new Argument (operand));
5762 IList<MemberSpec> GetConcatMethodCandidates ()
5764 return MemberCache.FindMembers (type, "Concat", true);
5767 public override void Emit (EmitContext ec)
5769 // Optimize by removing any extra null arguments, they are no-op
5770 for (int i = 0; i < arguments.Count; ++i) {
5771 if (arguments[i].Expr is NullConstant)
5772 arguments.RemoveAt (i--);
5775 var members = GetConcatMethodCandidates ();
5776 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5777 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5778 if (method != null) {
5779 var call = new CallEmitter ();
5780 call.EmitPredefined (ec, method, arguments, false);
5784 public override void FlowAnalysis (FlowAnalysisContext fc)
5786 arguments.FlowAnalysis (fc);
5789 public override SLE.Expression MakeExpression (BuilderContext ctx)
5791 if (arguments.Count != 2)
5792 throw new NotImplementedException ("arguments.Count != 2");
5794 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5795 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5800 // User-defined conditional logical operator
5802 public class ConditionalLogicalOperator : UserOperatorCall
5804 readonly bool is_and;
5805 Expression oper_expr;
5807 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5808 : base (oper, arguments, expr_tree, loc)
5810 this.is_and = is_and;
5811 eclass = ExprClass.Unresolved;
5814 protected override Expression DoResolve (ResolveContext ec)
5816 AParametersCollection pd = oper.Parameters;
5817 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5818 ec.Report.Error (217, loc,
5819 "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",
5820 oper.GetSignatureForError ());
5824 Expression left_dup = new EmptyExpression (type);
5825 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5826 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5827 if (op_true == null || op_false == null) {
5828 ec.Report.Error (218, loc,
5829 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5830 type.GetSignatureForError (), oper.GetSignatureForError ());
5834 oper_expr = is_and ? op_false : op_true;
5835 eclass = ExprClass.Value;
5839 public override void Emit (EmitContext ec)
5841 Label end_target = ec.DefineLabel ();
5844 // Emit and duplicate left argument
5846 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5847 if (right_contains_await) {
5848 arguments[0] = arguments[0].EmitToField (ec, false);
5849 arguments[0].Expr.Emit (ec);
5851 arguments[0].Expr.Emit (ec);
5852 ec.Emit (OpCodes.Dup);
5853 arguments.RemoveAt (0);
5856 oper_expr.EmitBranchable (ec, end_target, true);
5860 if (right_contains_await) {
5862 // Special handling when right expression contains await and left argument
5863 // could not be left on stack before logical branch
5865 Label skip_left_load = ec.DefineLabel ();
5866 ec.Emit (OpCodes.Br_S, skip_left_load);
5867 ec.MarkLabel (end_target);
5868 arguments[0].Expr.Emit (ec);
5869 ec.MarkLabel (skip_left_load);
5871 ec.MarkLabel (end_target);
5876 public class PointerArithmetic : Expression {
5877 Expression left, right;
5878 readonly Binary.Operator op;
5881 // We assume that `l' is always a pointer
5883 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5892 public override bool ContainsEmitWithAwait ()
5894 throw new NotImplementedException ();
5897 public override Expression CreateExpressionTree (ResolveContext ec)
5899 Error_PointerInsideExpressionTree (ec);
5903 protected override Expression DoResolve (ResolveContext ec)
5905 eclass = ExprClass.Variable;
5907 var pc = left.Type as PointerContainer;
5908 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5909 Error_VoidPointerOperation (ec);
5916 public override void Emit (EmitContext ec)
5918 TypeSpec op_type = left.Type;
5920 // It must be either array or fixed buffer
5922 if (TypeManager.HasElementType (op_type)) {
5923 element = TypeManager.GetElementType (op_type);
5925 FieldExpr fe = left as FieldExpr;
5927 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5932 int size = BuiltinTypeSpec.GetSize(element);
5933 TypeSpec rtype = right.Type;
5935 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5937 // handle (pointer - pointer)
5941 ec.Emit (OpCodes.Sub);
5945 ec.Emit (OpCodes.Sizeof, element);
5948 ec.Emit (OpCodes.Div);
5950 ec.Emit (OpCodes.Conv_I8);
5953 // handle + and - on (pointer op int)
5955 Constant left_const = left as Constant;
5956 if (left_const != null) {
5958 // Optimize ((T*)null) pointer operations
5960 if (left_const.IsDefaultValue) {
5961 left = EmptyExpression.Null;
5969 var right_const = right as Constant;
5970 if (right_const != null) {
5972 // Optimize 0-based arithmetic
5974 if (right_const.IsDefaultValue)
5978 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5980 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5982 // TODO: Should be the checks resolve context sensitive?
5983 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5984 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5990 switch (rtype.BuiltinType) {
5991 case BuiltinTypeSpec.Type.SByte:
5992 case BuiltinTypeSpec.Type.Byte:
5993 case BuiltinTypeSpec.Type.Short:
5994 case BuiltinTypeSpec.Type.UShort:
5995 ec.Emit (OpCodes.Conv_I);
5997 case BuiltinTypeSpec.Type.UInt:
5998 ec.Emit (OpCodes.Conv_U);
6002 if (right_const == null && size != 1){
6004 ec.Emit (OpCodes.Sizeof, element);
6007 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6008 ec.Emit (OpCodes.Conv_I8);
6010 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6013 if (left_const == null) {
6014 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6015 ec.Emit (OpCodes.Conv_I);
6016 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6017 ec.Emit (OpCodes.Conv_U);
6019 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6026 // A boolean-expression is an expression that yields a result
6029 public class BooleanExpression : ShimExpression
6031 public BooleanExpression (Expression expr)
6034 this.loc = expr.Location;
6037 public override Expression CreateExpressionTree (ResolveContext ec)
6039 // TODO: We should emit IsTrue (v4) instead of direct user operator
6040 // call but that would break csc compatibility
6041 return base.CreateExpressionTree (ec);
6044 protected override Expression DoResolve (ResolveContext ec)
6046 // A boolean-expression is required to be of a type
6047 // that can be implicitly converted to bool or of
6048 // a type that implements operator true
6050 expr = expr.Resolve (ec);
6054 Assign ass = expr as Assign;
6055 if (ass != null && ass.Source is Constant) {
6056 ec.Report.Warning (665, 3, loc,
6057 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6060 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6063 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6064 Arguments args = new Arguments (1);
6065 args.Add (new Argument (expr));
6066 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6069 type = ec.BuiltinTypes.Bool;
6070 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6071 if (converted != null)
6075 // If no implicit conversion to bool exists, try using `operator true'
6077 converted = GetOperatorTrue (ec, expr, loc);
6078 if (converted == null) {
6079 expr.Error_ValueCannotBeConverted (ec, type, false);
6086 public override object Accept (StructuralVisitor visitor)
6088 return visitor.Visit (this);
6092 public class BooleanExpressionFalse : Unary
6094 public BooleanExpressionFalse (Expression expr)
6095 : base (Operator.LogicalNot, expr, expr.Location)
6099 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6101 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6106 /// Implements the ternary conditional operator (?:)
6108 public class Conditional : Expression {
6109 Expression expr, true_expr, false_expr;
6111 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6114 this.true_expr = true_expr;
6115 this.false_expr = false_expr;
6121 public Expression Expr {
6127 public Expression TrueExpr {
6133 public Expression FalseExpr {
6141 public override bool ContainsEmitWithAwait ()
6143 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6146 public override Expression CreateExpressionTree (ResolveContext ec)
6148 Arguments args = new Arguments (3);
6149 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6150 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6151 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6152 return CreateExpressionFactoryCall (ec, "Condition", args);
6155 protected override Expression DoResolve (ResolveContext ec)
6157 expr = expr.Resolve (ec);
6158 true_expr = true_expr.Resolve (ec);
6159 false_expr = false_expr.Resolve (ec);
6161 if (true_expr == null || false_expr == null || expr == null)
6164 eclass = ExprClass.Value;
6165 TypeSpec true_type = true_expr.Type;
6166 TypeSpec false_type = false_expr.Type;
6170 // First, if an implicit conversion exists from true_expr
6171 // to false_expr, then the result type is of type false_expr.Type
6173 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6174 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6175 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6177 // Check if both can convert implicitly to each other's type
6181 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6182 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6184 // LAMESPEC: There seems to be hardcoded promotition to int type when
6185 // both sides are numeric constants and one side is int constant and
6186 // other side is numeric constant convertible to int.
6188 // var res = condition ? (short)1 : 1;
6190 // Type of res is int even if according to the spec the conversion is
6191 // ambiguous because 1 literal can be converted to short.
6193 if (conv_false_expr != null) {
6194 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6196 conv_false_expr = null;
6197 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6198 conv_false_expr = null;
6202 if (conv_false_expr != null) {
6203 ec.Report.Error (172, true_expr.Location,
6204 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6205 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6210 if (true_expr.Type != type)
6211 true_expr = EmptyCast.Create (true_expr, type);
6212 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6215 ec.Report.Error (173, true_expr.Location,
6216 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6217 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6222 Constant c = expr as Constant;
6224 bool is_false = c.IsDefaultValue;
6227 // Don't issue the warning for constant expressions
6229 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6230 // CSC: Missing warning
6231 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6234 return ReducedExpression.Create (
6235 is_false ? false_expr : true_expr, this,
6236 false_expr is Constant && true_expr is Constant).Resolve (ec);
6242 public override void Emit (EmitContext ec)
6244 Label false_target = ec.DefineLabel ();
6245 Label end_target = ec.DefineLabel ();
6247 expr.EmitBranchable (ec, false_target, false);
6248 true_expr.Emit (ec);
6251 // Verifier doesn't support interface merging. When there are two types on
6252 // the stack without common type hint and the common type is an interface.
6253 // Use temporary local to give verifier hint on what type to unify the stack
6255 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6256 var temp = ec.GetTemporaryLocal (type);
6257 ec.Emit (OpCodes.Stloc, temp);
6258 ec.Emit (OpCodes.Ldloc, temp);
6259 ec.FreeTemporaryLocal (temp, type);
6262 ec.Emit (OpCodes.Br, end_target);
6263 ec.MarkLabel (false_target);
6264 false_expr.Emit (ec);
6265 ec.MarkLabel (end_target);
6268 public override void FlowAnalysis (FlowAnalysisContext fc)
6270 expr.FlowAnalysisConditional (fc);
6271 var expr_true = fc.DefiniteAssignmentOnTrue;
6272 var expr_false = fc.DefiniteAssignmentOnFalse;
6274 fc.BranchDefiniteAssignment (expr_true);
6275 true_expr.FlowAnalysis (fc);
6276 var true_fc = fc.DefiniteAssignment;
6278 fc.BranchDefiniteAssignment (expr_false);
6279 false_expr.FlowAnalysis (fc);
6281 fc.DefiniteAssignment &= true_fc;
6284 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6286 expr.FlowAnalysisConditional (fc);
6287 var expr_true = fc.DefiniteAssignmentOnTrue;
6288 var expr_false = fc.DefiniteAssignmentOnFalse;
6290 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6291 true_expr.FlowAnalysisConditional (fc);
6292 var true_fc = fc.DefiniteAssignment;
6293 var true_da_true = fc.DefiniteAssignmentOnTrue;
6294 var true_da_false = fc.DefiniteAssignmentOnFalse;
6296 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6297 false_expr.FlowAnalysisConditional (fc);
6299 fc.DefiniteAssignment &= true_fc;
6300 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6301 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6304 protected override void CloneTo (CloneContext clonectx, Expression t)
6306 Conditional target = (Conditional) t;
6308 target.expr = expr.Clone (clonectx);
6309 target.true_expr = true_expr.Clone (clonectx);
6310 target.false_expr = false_expr.Clone (clonectx);
6314 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6316 LocalTemporary temp;
6319 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6320 public abstract void SetHasAddressTaken ();
6322 public abstract bool IsLockedByStatement { get; set; }
6324 public abstract bool IsFixed { get; }
6325 public abstract bool IsRef { get; }
6326 public abstract string Name { get; }
6329 // Variable IL data, it has to be protected to encapsulate hoisted variables
6331 protected abstract ILocalVariable Variable { get; }
6334 // Variable flow-analysis data
6336 public abstract VariableInfo VariableInfo { get; }
6339 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6341 HoistedVariable hv = GetHoistedVariable (ec);
6343 hv.AddressOf (ec, mode);
6347 Variable.EmitAddressOf (ec);
6350 public override bool ContainsEmitWithAwait ()
6355 public override Expression CreateExpressionTree (ResolveContext ec)
6357 HoistedVariable hv = GetHoistedVariable (ec);
6359 return hv.CreateExpressionTree ();
6361 Arguments arg = new Arguments (1);
6362 arg.Add (new Argument (this));
6363 return CreateExpressionFactoryCall (ec, "Constant", arg);
6366 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6368 if (IsLockedByStatement) {
6369 rc.Report.Warning (728, 2, loc,
6370 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6377 public override void Emit (EmitContext ec)
6382 public override void EmitSideEffect (EmitContext ec)
6388 // This method is used by parameters that are references, that are
6389 // being passed as references: we only want to pass the pointer (that
6390 // is already stored in the parameter, not the address of the pointer,
6391 // and not the value of the variable).
6393 public void EmitLoad (EmitContext ec)
6398 public void Emit (EmitContext ec, bool leave_copy)
6400 HoistedVariable hv = GetHoistedVariable (ec);
6402 hv.Emit (ec, leave_copy);
6410 // If we are a reference, we loaded on the stack a pointer
6411 // Now lets load the real value
6413 ec.EmitLoadFromPtr (type);
6417 ec.Emit (OpCodes.Dup);
6420 temp = new LocalTemporary (Type);
6426 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6427 bool prepare_for_load)
6429 HoistedVariable hv = GetHoistedVariable (ec);
6431 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6435 New n_source = source as New;
6436 if (n_source != null) {
6437 if (!n_source.Emit (ec, this)) {
6441 ec.EmitLoadFromPtr (type);
6453 ec.Emit (OpCodes.Dup);
6455 temp = new LocalTemporary (Type);
6461 ec.EmitStoreFromPtr (type);
6463 Variable.EmitAssign (ec);
6471 public override Expression EmitToField (EmitContext ec)
6473 HoistedVariable hv = GetHoistedVariable (ec);
6475 return hv.EmitToField (ec);
6478 return base.EmitToField (ec);
6481 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6483 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6486 public HoistedVariable GetHoistedVariable (EmitContext ec)
6488 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6491 public override string GetSignatureForError ()
6496 public bool IsHoisted {
6497 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6502 // Resolved reference to a local variable
6504 public class LocalVariableReference : VariableReference
6506 public LocalVariable local_info;
6508 public LocalVariableReference (LocalVariable li, Location l)
6510 this.local_info = li;
6514 public override VariableInfo VariableInfo {
6515 get { return local_info.VariableInfo; }
6518 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6520 return local_info.HoistedVariant;
6526 // A local variable is always fixed
6528 public override bool IsFixed {
6534 public override bool IsLockedByStatement {
6536 return local_info.IsLocked;
6539 local_info.IsLocked = value;
6543 public override bool IsRef {
6544 get { return false; }
6547 public override string Name {
6548 get { return local_info.Name; }
6553 public override void FlowAnalysis (FlowAnalysisContext fc)
6555 VariableInfo variable_info = VariableInfo;
6556 if (variable_info == null)
6559 if (fc.IsDefinitelyAssigned (variable_info))
6562 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6563 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6566 public override void SetHasAddressTaken ()
6568 local_info.SetHasAddressTaken ();
6571 void DoResolveBase (ResolveContext ec)
6573 eclass = ExprClass.Variable;
6574 type = local_info.Type;
6577 // If we are referencing a variable from the external block
6578 // flag it for capturing
6580 if (ec.MustCaptureVariable (local_info)) {
6581 if (local_info.AddressTaken) {
6582 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6583 } else if (local_info.IsFixed) {
6584 ec.Report.Error (1764, loc,
6585 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6586 GetSignatureForError ());
6589 if (ec.IsVariableCapturingRequired) {
6590 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6591 storey.CaptureLocalVariable (ec, local_info);
6596 protected override Expression DoResolve (ResolveContext ec)
6598 local_info.SetIsUsed ();
6602 if (local_info.Type == InternalType.VarOutType) {
6603 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6604 GetSignatureForError ());
6606 type = InternalType.ErrorType;
6612 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6615 // Don't be too pedantic when variable is used as out param or for some broken code
6616 // which uses property/indexer access to run some initialization
6618 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6619 local_info.SetIsUsed ();
6621 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6622 if (rhs == EmptyExpression.LValueMemberAccess) {
6623 // CS1654 already reported
6627 if (rhs == EmptyExpression.OutAccess) {
6628 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6629 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6630 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6631 } else if (rhs == EmptyExpression.UnaryAddress) {
6632 code = 459; msg = "Cannot take the address of {1} `{0}'";
6634 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6636 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6640 if (eclass == ExprClass.Unresolved)
6643 return base.DoResolveLValue (ec, rhs);
6646 public override int GetHashCode ()
6648 return local_info.GetHashCode ();
6651 public override bool Equals (object obj)
6653 LocalVariableReference lvr = obj as LocalVariableReference;
6657 return local_info == lvr.local_info;
6660 protected override ILocalVariable Variable {
6661 get { return local_info; }
6664 public override string ToString ()
6666 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6669 protected override void CloneTo (CloneContext clonectx, Expression t)
6676 /// This represents a reference to a parameter in the intermediate
6679 public class ParameterReference : VariableReference
6681 protected ParametersBlock.ParameterInfo pi;
6683 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6691 public override bool IsLockedByStatement {
6696 pi.IsLocked = value;
6700 public override bool IsRef {
6701 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6704 bool HasOutModifier {
6705 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6708 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6710 return pi.Parameter.HoistedVariant;
6714 // A ref or out parameter is classified as a moveable variable, even
6715 // if the argument given for the parameter is a fixed variable
6717 public override bool IsFixed {
6718 get { return !IsRef; }
6721 public override string Name {
6722 get { return Parameter.Name; }
6725 public Parameter Parameter {
6726 get { return pi.Parameter; }
6729 public override VariableInfo VariableInfo {
6730 get { return pi.VariableInfo; }
6733 protected override ILocalVariable Variable {
6734 get { return Parameter; }
6739 public override void AddressOf (EmitContext ec, AddressOp mode)
6742 // ParameterReferences might already be a reference
6749 base.AddressOf (ec, mode);
6752 public override void SetHasAddressTaken ()
6754 Parameter.HasAddressTaken = true;
6757 bool DoResolveBase (ResolveContext ec)
6759 if (eclass != ExprClass.Unresolved)
6762 type = pi.ParameterType;
6763 eclass = ExprClass.Variable;
6766 // If we are referencing a parameter from the external block
6767 // flag it for capturing
6769 if (ec.MustCaptureVariable (pi)) {
6770 if (Parameter.HasAddressTaken)
6771 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6774 ec.Report.Error (1628, loc,
6775 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6776 Name, ec.CurrentAnonymousMethod.ContainerType);
6779 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6780 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6781 storey.CaptureParameter (ec, pi, this);
6788 public override int GetHashCode ()
6790 return Name.GetHashCode ();
6793 public override bool Equals (object obj)
6795 ParameterReference pr = obj as ParameterReference;
6799 return Name == pr.Name;
6802 protected override void CloneTo (CloneContext clonectx, Expression target)
6808 public override Expression CreateExpressionTree (ResolveContext ec)
6810 HoistedVariable hv = GetHoistedVariable (ec);
6812 return hv.CreateExpressionTree ();
6814 return Parameter.ExpressionTreeVariableReference ();
6817 protected override Expression DoResolve (ResolveContext ec)
6819 if (!DoResolveBase (ec))
6825 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6827 if (!DoResolveBase (ec))
6830 if (Parameter.HoistedVariant != null)
6831 Parameter.HoistedVariant.IsAssigned = true;
6833 return base.DoResolveLValue (ec, right_side);
6836 public override void FlowAnalysis (FlowAnalysisContext fc)
6838 VariableInfo variable_info = VariableInfo;
6839 if (variable_info == null)
6842 if (fc.IsDefinitelyAssigned (variable_info))
6845 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6846 fc.SetVariableAssigned (variable_info);
6851 /// Invocation of methods or delegates.
6853 public class Invocation : ExpressionStatement
6855 public class Predefined : Invocation
6857 public Predefined (MethodGroupExpr expr, Arguments arguments)
6858 : base (expr, arguments)
6863 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6865 if (!rc.IsObsolete) {
6866 var member = mg.BestCandidate;
6867 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6869 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6876 protected Arguments arguments;
6877 protected Expression expr;
6878 protected MethodGroupExpr mg;
6879 bool conditional_access_receiver;
6881 public Invocation (Expression expr, Arguments arguments)
6884 this.arguments = arguments;
6886 loc = expr.Location;
6891 public Arguments Arguments {
6897 public Expression Exp {
6903 public MethodGroupExpr MethodGroup {
6909 public override Location StartLocation {
6911 return expr.StartLocation;
6917 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6919 if (MethodGroup == null)
6922 var candidate = MethodGroup.BestCandidate;
6923 if (candidate == null || !(candidate.IsStatic || Exp is This))
6926 var args_count = arguments == null ? 0 : arguments.Count;
6927 if (args_count != body.Parameters.Count)
6930 var lambda_parameters = body.Block.Parameters.FixedParameters;
6931 for (int i = 0; i < args_count; ++i) {
6932 var pr = arguments[i].Expr as ParameterReference;
6936 if (lambda_parameters[i] != pr.Parameter)
6939 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6943 var emg = MethodGroup as ExtensionMethodGroupExpr;
6945 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6946 if (candidate.IsGeneric) {
6947 var targs = new TypeExpression [candidate.Arity];
6948 for (int i = 0; i < targs.Length; ++i) {
6949 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6952 mg.SetTypeArguments (null, new TypeArguments (targs));
6961 protected override void CloneTo (CloneContext clonectx, Expression t)
6963 Invocation target = (Invocation) t;
6965 if (arguments != null)
6966 target.arguments = arguments.Clone (clonectx);
6968 target.expr = expr.Clone (clonectx);
6971 public override bool ContainsEmitWithAwait ()
6973 if (arguments != null && arguments.ContainsEmitWithAwait ())
6976 return mg.ContainsEmitWithAwait ();
6979 public override Expression CreateExpressionTree (ResolveContext ec)
6981 Expression instance = mg.IsInstance ?
6982 mg.InstanceExpression.CreateExpressionTree (ec) :
6983 new NullLiteral (loc);
6985 var args = Arguments.CreateForExpressionTree (ec, arguments,
6987 mg.CreateExpressionTree (ec));
6989 return CreateExpressionFactoryCall (ec, "Call", args);
6992 protected override Expression DoResolve (ResolveContext rc)
6994 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
6995 if (expr.HasConditionalAccess ()) {
6996 conditional_access_receiver = true;
6997 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
6998 return DoResolveInvocation (rc);
7003 return DoResolveInvocation (rc);
7006 Expression DoResolveInvocation (ResolveContext ec)
7008 Expression member_expr;
7009 var atn = expr as ATypeNameExpression;
7011 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7012 if (member_expr != null) {
7013 var name_of = member_expr as NameOf;
7014 if (name_of != null) {
7015 return name_of.ResolveOverload (ec, arguments);
7018 member_expr = member_expr.Resolve (ec);
7021 member_expr = expr.Resolve (ec);
7024 if (member_expr == null)
7028 // Next, evaluate all the expressions in the argument list
7030 bool dynamic_arg = false;
7031 if (arguments != null)
7032 arguments.Resolve (ec, out dynamic_arg);
7034 TypeSpec expr_type = member_expr.Type;
7035 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7036 return DoResolveDynamic (ec, member_expr);
7038 mg = member_expr as MethodGroupExpr;
7039 Expression invoke = null;
7042 if (expr_type != null && expr_type.IsDelegate) {
7043 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7044 invoke = invoke.Resolve (ec);
7045 if (invoke == null || !dynamic_arg)
7048 if (member_expr is RuntimeValueExpression) {
7049 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7050 member_expr.Type.GetSignatureForError ());
7054 MemberExpr me = member_expr as MemberExpr;
7056 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7060 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7061 member_expr.GetSignatureForError ());
7066 if (invoke == null) {
7067 mg = DoResolveOverload (ec);
7073 return DoResolveDynamic (ec, member_expr);
7075 var method = mg.BestCandidate;
7076 type = mg.BestCandidateReturnType;
7077 if (conditional_access_receiver)
7078 type = LiftMemberType (ec, type);
7080 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7082 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7084 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7088 IsSpecialMethodInvocation (ec, method, loc);
7090 eclass = ExprClass.Value;
7094 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7097 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7099 args = dmb.Arguments;
7100 if (arguments != null)
7101 args.AddRange (arguments);
7102 } else if (mg == null) {
7103 if (arguments == null)
7104 args = new Arguments (1);
7108 args.Insert (0, new Argument (memberExpr));
7112 ec.Report.Error (1971, loc,
7113 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7118 if (arguments == null)
7119 args = new Arguments (1);
7123 MemberAccess ma = expr as MemberAccess;
7125 var inst = mg.InstanceExpression;
7126 var left_type = inst as TypeExpr;
7127 if (left_type != null) {
7128 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7129 } else if (inst != null) {
7131 // Any value type has to be pass as by-ref to get back the same
7132 // instance on which the member was called
7134 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7135 Argument.AType.Ref : Argument.AType.None;
7136 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7138 } else { // is SimpleName
7140 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7142 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7147 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7150 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7152 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7155 public override void FlowAnalysis (FlowAnalysisContext fc)
7157 if (mg.IsConditionallyExcluded)
7160 mg.FlowAnalysis (fc);
7162 if (arguments != null)
7163 arguments.FlowAnalysis (fc);
7165 if (conditional_access_receiver)
7166 fc.ConditionalAccessEnd ();
7169 public override string GetSignatureForError ()
7171 return mg.GetSignatureForError ();
7174 public override bool HasConditionalAccess ()
7176 return expr.HasConditionalAccess ();
7180 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7181 // or the type dynamic, then the member is invocable
7183 public static bool IsMemberInvocable (MemberSpec member)
7185 switch (member.Kind) {
7186 case MemberKind.Event:
7188 case MemberKind.Field:
7189 case MemberKind.Property:
7190 var m = member as IInterfaceMemberSpec;
7191 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7197 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7199 if (!method.IsReservedMethod)
7202 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7205 ec.Report.SymbolRelatedToPreviousError (method);
7206 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7207 method.GetSignatureForError ());
7212 public override void Emit (EmitContext ec)
7214 if (mg.IsConditionallyExcluded)
7217 if (conditional_access_receiver)
7218 mg.EmitCall (ec, arguments, type, false);
7220 mg.EmitCall (ec, arguments, false);
7223 public override void EmitStatement (EmitContext ec)
7225 if (mg.IsConditionallyExcluded)
7228 if (conditional_access_receiver)
7229 mg.EmitCall (ec, arguments, type, true);
7231 mg.EmitCall (ec, arguments, true);
7234 public override SLE.Expression MakeExpression (BuilderContext ctx)
7236 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7239 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7242 throw new NotSupportedException ();
7244 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7245 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7249 public override object Accept (StructuralVisitor visitor)
7251 return visitor.Visit (this);
7256 // Implements simple new expression
7258 public class New : ExpressionStatement, IMemoryLocation
7260 protected Arguments arguments;
7263 // During bootstrap, it contains the RequestedType,
7264 // but if `type' is not null, it *might* contain a NewDelegate
7265 // (because of field multi-initialization)
7267 protected Expression RequestedType;
7269 protected MethodSpec method;
7271 public New (Expression requested_type, Arguments arguments, Location l)
7273 RequestedType = requested_type;
7274 this.arguments = arguments;
7279 public Arguments Arguments {
7286 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7288 public bool IsGeneratedStructConstructor {
7290 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7294 public Expression TypeExpression {
7296 return RequestedType;
7303 /// Converts complex core type syntax like 'new int ()' to simple constant
7305 public static Constant Constantify (TypeSpec t, Location loc)
7307 switch (t.BuiltinType) {
7308 case BuiltinTypeSpec.Type.Int:
7309 return new IntConstant (t, 0, loc);
7310 case BuiltinTypeSpec.Type.UInt:
7311 return new UIntConstant (t, 0, loc);
7312 case BuiltinTypeSpec.Type.Long:
7313 return new LongConstant (t, 0, loc);
7314 case BuiltinTypeSpec.Type.ULong:
7315 return new ULongConstant (t, 0, loc);
7316 case BuiltinTypeSpec.Type.Float:
7317 return new FloatConstant (t, 0, loc);
7318 case BuiltinTypeSpec.Type.Double:
7319 return new DoubleConstant (t, 0, loc);
7320 case BuiltinTypeSpec.Type.Short:
7321 return new ShortConstant (t, 0, loc);
7322 case BuiltinTypeSpec.Type.UShort:
7323 return new UShortConstant (t, 0, loc);
7324 case BuiltinTypeSpec.Type.SByte:
7325 return new SByteConstant (t, 0, loc);
7326 case BuiltinTypeSpec.Type.Byte:
7327 return new ByteConstant (t, 0, loc);
7328 case BuiltinTypeSpec.Type.Char:
7329 return new CharConstant (t, '\0', loc);
7330 case BuiltinTypeSpec.Type.Bool:
7331 return new BoolConstant (t, false, loc);
7332 case BuiltinTypeSpec.Type.Decimal:
7333 return new DecimalConstant (t, 0, loc);
7337 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7339 if (t.IsNullableType)
7340 return Nullable.LiftedNull.Create (t, loc);
7345 public override bool ContainsEmitWithAwait ()
7347 return arguments != null && arguments.ContainsEmitWithAwait ();
7351 // Checks whether the type is an interface that has the
7352 // [ComImport, CoClass] attributes and must be treated
7355 public Expression CheckComImport (ResolveContext ec)
7357 if (!type.IsInterface)
7361 // Turn the call into:
7362 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7364 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7365 if (real_class == null)
7368 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7369 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7370 return cast.Resolve (ec);
7373 public override Expression CreateExpressionTree (ResolveContext ec)
7376 if (method == null) {
7377 args = new Arguments (1);
7378 args.Add (new Argument (new TypeOf (type, loc)));
7380 args = Arguments.CreateForExpressionTree (ec,
7381 arguments, new TypeOfMethod (method, loc));
7384 return CreateExpressionFactoryCall (ec, "New", args);
7387 protected override Expression DoResolve (ResolveContext ec)
7389 type = RequestedType.ResolveAsType (ec);
7393 eclass = ExprClass.Value;
7395 if (type.IsPointer) {
7396 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7397 type.GetSignatureForError ());
7401 if (arguments == null) {
7402 Constant c = Constantify (type, RequestedType.Location);
7404 return ReducedExpression.Create (c, this);
7407 if (type.IsDelegate) {
7408 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7411 var tparam = type as TypeParameterSpec;
7412 if (tparam != null) {
7414 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7415 // where type parameter constraint is inflated to struct
7417 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7418 ec.Report.Error (304, loc,
7419 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7420 type.GetSignatureForError ());
7423 if ((arguments != null) && (arguments.Count != 0)) {
7424 ec.Report.Error (417, loc,
7425 "`{0}': cannot provide arguments when creating an instance of a variable type",
7426 type.GetSignatureForError ());
7432 if (type.IsStatic) {
7433 ec.Report.SymbolRelatedToPreviousError (type);
7434 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7438 if (type.IsInterface || type.IsAbstract){
7439 if (!TypeManager.IsGenericType (type)) {
7440 RequestedType = CheckComImport (ec);
7441 if (RequestedType != null)
7442 return RequestedType;
7445 ec.Report.SymbolRelatedToPreviousError (type);
7446 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7451 if (arguments != null) {
7452 arguments.Resolve (ec, out dynamic);
7457 method = ConstructorLookup (ec, type, ref arguments, loc);
7460 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7461 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7467 void DoEmitTypeParameter (EmitContext ec)
7469 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7473 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7474 ec.Emit (OpCodes.Call, ctor_factory);
7478 // This Emit can be invoked in two contexts:
7479 // * As a mechanism that will leave a value on the stack (new object)
7480 // * As one that wont (init struct)
7482 // If we are dealing with a ValueType, we have a few
7483 // situations to deal with:
7485 // * The target is a ValueType, and we have been provided
7486 // the instance (this is easy, we are being assigned).
7488 // * The target of New is being passed as an argument,
7489 // to a boxing operation or a function that takes a
7492 // In this case, we need to create a temporary variable
7493 // that is the argument of New.
7495 // Returns whether a value is left on the stack
7497 // *** Implementation note ***
7499 // To benefit from this optimization, each assignable expression
7500 // has to manually cast to New and call this Emit.
7502 // TODO: It's worth to implement it for arrays and fields
7504 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7506 bool is_value_type = type.IsStructOrEnum;
7507 VariableReference vr = target as VariableReference;
7509 if (target != null && is_value_type && (vr != null || method == null)) {
7510 target.AddressOf (ec, AddressOp.Store);
7511 } else if (vr != null && vr.IsRef) {
7515 if (arguments != null) {
7516 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7517 arguments = arguments.Emit (ec, false, true);
7519 arguments.Emit (ec);
7522 if (is_value_type) {
7523 if (method == null) {
7524 ec.Emit (OpCodes.Initobj, type);
7529 ec.MarkCallEntry (loc);
7530 ec.Emit (OpCodes.Call, method);
7535 if (type is TypeParameterSpec) {
7536 DoEmitTypeParameter (ec);
7540 ec.MarkCallEntry (loc);
7541 ec.Emit (OpCodes.Newobj, method);
7545 public override void Emit (EmitContext ec)
7547 LocalTemporary v = null;
7548 if (method == null && type.IsStructOrEnum) {
7549 // TODO: Use temporary variable from pool
7550 v = new LocalTemporary (type);
7557 public override void EmitStatement (EmitContext ec)
7559 LocalTemporary v = null;
7560 if (method == null && TypeSpec.IsValueType (type)) {
7561 // TODO: Use temporary variable from pool
7562 v = new LocalTemporary (type);
7566 ec.Emit (OpCodes.Pop);
7569 public override void FlowAnalysis (FlowAnalysisContext fc)
7571 if (arguments != null)
7572 arguments.FlowAnalysis (fc);
7575 public void AddressOf (EmitContext ec, AddressOp mode)
7577 EmitAddressOf (ec, mode);
7580 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7582 LocalTemporary value_target = new LocalTemporary (type);
7584 if (type is TypeParameterSpec) {
7585 DoEmitTypeParameter (ec);
7586 value_target.Store (ec);
7587 value_target.AddressOf (ec, mode);
7588 return value_target;
7591 value_target.AddressOf (ec, AddressOp.Store);
7593 if (method == null) {
7594 ec.Emit (OpCodes.Initobj, type);
7596 if (arguments != null)
7597 arguments.Emit (ec);
7599 ec.Emit (OpCodes.Call, method);
7602 value_target.AddressOf (ec, mode);
7603 return value_target;
7606 protected override void CloneTo (CloneContext clonectx, Expression t)
7608 New target = (New) t;
7610 target.RequestedType = RequestedType.Clone (clonectx);
7611 if (arguments != null){
7612 target.arguments = arguments.Clone (clonectx);
7616 public override SLE.Expression MakeExpression (BuilderContext ctx)
7619 return base.MakeExpression (ctx);
7621 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7625 public override object Accept (StructuralVisitor visitor)
7627 return visitor.Visit (this);
7632 // Array initializer expression, the expression is allowed in
7633 // variable or field initialization only which makes it tricky as
7634 // the type has to be infered based on the context either from field
7635 // type or variable type (think of multiple declarators)
7637 public class ArrayInitializer : Expression
7639 List<Expression> elements;
7640 BlockVariable variable;
7642 public ArrayInitializer (List<Expression> init, Location loc)
7648 public ArrayInitializer (int count, Location loc)
7649 : this (new List<Expression> (count), loc)
7653 public ArrayInitializer (Location loc)
7661 get { return elements.Count; }
7664 public List<Expression> Elements {
7670 public Expression this [int index] {
7672 return elements [index];
7676 public BlockVariable VariableDeclaration {
7687 public void Add (Expression expr)
7689 elements.Add (expr);
7692 public override bool ContainsEmitWithAwait ()
7694 throw new NotSupportedException ();
7697 public override Expression CreateExpressionTree (ResolveContext ec)
7699 throw new NotSupportedException ("ET");
7702 protected override void CloneTo (CloneContext clonectx, Expression t)
7704 var target = (ArrayInitializer) t;
7706 target.elements = new List<Expression> (elements.Count);
7707 foreach (var element in elements)
7708 target.elements.Add (element.Clone (clonectx));
7711 protected override Expression DoResolve (ResolveContext rc)
7713 var current_field = rc.CurrentMemberDefinition as FieldBase;
7714 TypeExpression type;
7715 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7716 type = new TypeExpression (current_field.MemberType, current_field.Location);
7717 } else if (variable != null) {
7718 if (variable.TypeExpression is VarExpr) {
7719 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7720 return EmptyExpression.Null;
7723 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7725 throw new NotImplementedException ("Unexpected array initializer context");
7728 return new ArrayCreation (type, this).Resolve (rc);
7731 public override void Emit (EmitContext ec)
7733 throw new InternalErrorException ("Missing Resolve call");
7736 public override void FlowAnalysis (FlowAnalysisContext fc)
7738 throw new InternalErrorException ("Missing Resolve call");
7741 public override object Accept (StructuralVisitor visitor)
7743 return visitor.Visit (this);
7748 /// 14.5.10.2: Represents an array creation expression.
7752 /// There are two possible scenarios here: one is an array creation
7753 /// expression that specifies the dimensions and optionally the
7754 /// initialization data and the other which does not need dimensions
7755 /// specified but where initialization data is mandatory.
7757 public class ArrayCreation : Expression
7759 FullNamedExpression requested_base_type;
7760 ArrayInitializer initializers;
7763 // The list of Argument types.
7764 // This is used to construct the `newarray' or constructor signature
7766 protected List<Expression> arguments;
7768 protected TypeSpec array_element_type;
7770 protected int dimensions;
7771 protected readonly ComposedTypeSpecifier rank;
7772 Expression first_emit;
7773 LocalTemporary first_emit_temp;
7775 protected List<Expression> array_data;
7777 Dictionary<int, int> bounds;
7780 // The number of constants in array initializers
7781 int const_initializers_count;
7782 bool only_constant_initializers;
7784 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7785 : this (requested_base_type, rank, initializers, l)
7787 arguments = new List<Expression> (exprs);
7788 num_arguments = arguments.Count;
7792 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7794 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7796 this.requested_base_type = requested_base_type;
7798 this.initializers = initializers;
7802 num_arguments = rank.Dimension;
7806 // For compiler generated single dimensional arrays only
7808 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7809 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7814 // For expressions like int[] foo = { 1, 2, 3 };
7816 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7817 : this (requested_base_type, null, initializers, initializers.Location)
7821 public ComposedTypeSpecifier Rank {
7827 public FullNamedExpression TypeExpression {
7829 return this.requested_base_type;
7833 public ArrayInitializer Initializers {
7835 return this.initializers;
7839 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7841 if (initializers != null && bounds == null) {
7843 // We use this to store all the data values in the order in which we
7844 // will need to store them in the byte blob later
7846 array_data = new List<Expression> (probe.Count);
7847 bounds = new Dictionary<int, int> ();
7850 if (specified_dims) {
7851 Expression a = arguments [idx];
7856 a = ConvertExpressionToArrayIndex (ec, a);
7862 if (initializers != null) {
7863 Constant c = a as Constant;
7864 if (c == null && a is ArrayIndexCast)
7865 c = ((ArrayIndexCast) a).Child as Constant;
7868 ec.Report.Error (150, a.Location, "A constant value is expected");
7874 value = System.Convert.ToInt32 (c.GetValue ());
7876 ec.Report.Error (150, a.Location, "A constant value is expected");
7880 // TODO: probe.Count does not fit ulong in
7881 if (value != probe.Count) {
7882 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7886 bounds[idx] = value;
7890 if (initializers == null)
7893 for (int i = 0; i < probe.Count; ++i) {
7895 if (o is ArrayInitializer) {
7896 var sub_probe = o as ArrayInitializer;
7897 if (idx + 1 >= dimensions){
7898 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7902 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7903 if (!bounds.ContainsKey(idx + 1))
7904 bounds[idx + 1] = sub_probe.Count;
7906 if (bounds[idx + 1] != sub_probe.Count) {
7907 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7911 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7914 } else if (child_bounds > 1) {
7915 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7917 Expression element = ResolveArrayElement (ec, o);
7918 if (element == null)
7921 // Initializers with the default values can be ignored
7922 Constant c = element as Constant;
7924 if (!c.IsDefaultInitializer (array_element_type)) {
7925 ++const_initializers_count;
7928 only_constant_initializers = false;
7931 array_data.Add (element);
7938 public override bool ContainsEmitWithAwait ()
7940 foreach (var arg in arguments) {
7941 if (arg.ContainsEmitWithAwait ())
7945 return InitializersContainAwait ();
7948 public override Expression CreateExpressionTree (ResolveContext ec)
7952 if (array_data == null) {
7953 args = new Arguments (arguments.Count + 1);
7954 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7955 foreach (Expression a in arguments)
7956 args.Add (new Argument (a.CreateExpressionTree (ec)));
7958 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7961 if (dimensions > 1) {
7962 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7966 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7967 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7968 if (array_data != null) {
7969 for (int i = 0; i < array_data.Count; ++i) {
7970 Expression e = array_data [i];
7971 args.Add (new Argument (e.CreateExpressionTree (ec)));
7975 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7978 void UpdateIndices (ResolveContext rc)
7981 for (var probe = initializers; probe != null;) {
7982 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7984 bounds[i++] = probe.Count;
7986 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7987 probe = (ArrayInitializer) probe[0];
7988 } else if (dimensions > i) {
7996 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7998 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8001 public override void FlowAnalysis (FlowAnalysisContext fc)
8003 foreach (var arg in arguments)
8004 arg.FlowAnalysis (fc);
8006 if (array_data != null) {
8007 foreach (var ad in array_data)
8008 ad.FlowAnalysis (fc);
8012 bool InitializersContainAwait ()
8014 if (array_data == null)
8017 foreach (var expr in array_data) {
8018 if (expr.ContainsEmitWithAwait ())
8025 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8027 element = element.Resolve (ec);
8028 if (element == null)
8031 if (element is CompoundAssign.TargetExpression) {
8032 if (first_emit != null)
8033 throw new InternalErrorException ("Can only handle one mutator at a time");
8034 first_emit = element;
8035 element = first_emit_temp = new LocalTemporary (element.Type);
8038 return Convert.ImplicitConversionRequired (
8039 ec, element, array_element_type, loc);
8042 protected bool ResolveInitializers (ResolveContext ec)
8045 only_constant_initializers = true;
8048 if (arguments != null) {
8050 for (int i = 0; i < arguments.Count; ++i) {
8051 res &= CheckIndices (ec, initializers, i, true, dimensions);
8052 if (initializers != null)
8059 arguments = new List<Expression> ();
8061 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8070 // Resolved the type of the array
8072 bool ResolveArrayType (ResolveContext ec)
8077 FullNamedExpression array_type_expr;
8078 if (num_arguments > 0) {
8079 array_type_expr = new ComposedCast (requested_base_type, rank);
8081 array_type_expr = requested_base_type;
8084 type = array_type_expr.ResolveAsType (ec);
8085 if (array_type_expr == null)
8088 var ac = type as ArrayContainer;
8090 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8094 array_element_type = ac.Element;
8095 dimensions = ac.Rank;
8100 protected override Expression DoResolve (ResolveContext ec)
8105 if (!ResolveArrayType (ec))
8109 // validate the initializers and fill in any missing bits
8111 if (!ResolveInitializers (ec))
8114 eclass = ExprClass.Value;
8118 byte [] MakeByteBlob ()
8123 int count = array_data.Count;
8125 TypeSpec element_type = array_element_type;
8126 if (element_type.IsEnum)
8127 element_type = EnumSpec.GetUnderlyingType (element_type);
8129 factor = BuiltinTypeSpec.GetSize (element_type);
8131 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8133 data = new byte [(count * factor + 3) & ~3];
8136 for (int i = 0; i < count; ++i) {
8137 var c = array_data[i] as Constant;
8143 object v = c.GetValue ();
8145 switch (element_type.BuiltinType) {
8146 case BuiltinTypeSpec.Type.Long:
8147 long lval = (long) v;
8149 for (int j = 0; j < factor; ++j) {
8150 data[idx + j] = (byte) (lval & 0xFF);
8154 case BuiltinTypeSpec.Type.ULong:
8155 ulong ulval = (ulong) v;
8157 for (int j = 0; j < factor; ++j) {
8158 data[idx + j] = (byte) (ulval & 0xFF);
8159 ulval = (ulval >> 8);
8162 case BuiltinTypeSpec.Type.Float:
8163 var fval = SingleConverter.SingleToInt32Bits((float) v);
8165 data[idx] = (byte) (fval & 0xff);
8166 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8167 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8168 data[idx + 3] = (byte) (fval >> 24);
8170 case BuiltinTypeSpec.Type.Double:
8171 element = BitConverter.GetBytes ((double) v);
8173 for (int j = 0; j < factor; ++j)
8174 data[idx + j] = element[j];
8176 // FIXME: Handle the ARM float format.
8177 if (!BitConverter.IsLittleEndian)
8178 System.Array.Reverse (data, idx, 8);
8180 case BuiltinTypeSpec.Type.Char:
8181 int chval = (int) ((char) v);
8183 data[idx] = (byte) (chval & 0xff);
8184 data[idx + 1] = (byte) (chval >> 8);
8186 case BuiltinTypeSpec.Type.Short:
8187 int sval = (int) ((short) v);
8189 data[idx] = (byte) (sval & 0xff);
8190 data[idx + 1] = (byte) (sval >> 8);
8192 case BuiltinTypeSpec.Type.UShort:
8193 int usval = (int) ((ushort) v);
8195 data[idx] = (byte) (usval & 0xff);
8196 data[idx + 1] = (byte) (usval >> 8);
8198 case BuiltinTypeSpec.Type.Int:
8201 data[idx] = (byte) (val & 0xff);
8202 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8203 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8204 data[idx + 3] = (byte) (val >> 24);
8206 case BuiltinTypeSpec.Type.UInt:
8207 uint uval = (uint) v;
8209 data[idx] = (byte) (uval & 0xff);
8210 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8211 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8212 data[idx + 3] = (byte) (uval >> 24);
8214 case BuiltinTypeSpec.Type.SByte:
8215 data[idx] = (byte) (sbyte) v;
8217 case BuiltinTypeSpec.Type.Byte:
8218 data[idx] = (byte) v;
8220 case BuiltinTypeSpec.Type.Bool:
8221 data[idx] = (byte) ((bool) v ? 1 : 0);
8223 case BuiltinTypeSpec.Type.Decimal:
8224 int[] bits = Decimal.GetBits ((decimal) v);
8227 // FIXME: For some reason, this doesn't work on the MS runtime.
8228 int[] nbits = new int[4];
8234 for (int j = 0; j < 4; j++) {
8235 data[p++] = (byte) (nbits[j] & 0xff);
8236 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8237 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8238 data[p++] = (byte) (nbits[j] >> 24);
8242 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8251 #if NET_4_0 || MOBILE_DYNAMIC
8252 public override SLE.Expression MakeExpression (BuilderContext ctx)
8255 return base.MakeExpression (ctx);
8257 var initializers = new SLE.Expression [array_data.Count];
8258 for (var i = 0; i < initializers.Length; i++) {
8259 if (array_data [i] == null)
8260 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8262 initializers [i] = array_data [i].MakeExpression (ctx);
8265 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8271 // Emits the initializers for the array
8273 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8275 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8280 // First, the static data
8282 byte [] data = MakeByteBlob ();
8283 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8285 if (stackArray == null) {
8286 ec.Emit (OpCodes.Dup);
8288 stackArray.Emit (ec);
8291 ec.Emit (OpCodes.Ldtoken, fb);
8292 ec.Emit (OpCodes.Call, m);
8297 // Emits pieces of the array that can not be computed at compile
8298 // time (variables and string locations).
8300 // This always expect the top value on the stack to be the array
8302 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8304 int dims = bounds.Count;
8305 var current_pos = new int [dims];
8307 for (int i = 0; i < array_data.Count; i++){
8309 Expression e = array_data [i];
8310 var c = e as Constant;
8312 // Constant can be initialized via StaticInitializer
8313 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8317 if (stackArray != null) {
8318 if (e.ContainsEmitWithAwait ()) {
8319 e = e.EmitToField (ec);
8322 stackArray.EmitLoad (ec);
8324 ec.Emit (OpCodes.Dup);
8327 for (int idx = 0; idx < dims; idx++)
8328 ec.EmitInt (current_pos [idx]);
8331 // If we are dealing with a struct, get the
8332 // address of it, so we can store it.
8334 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8335 ec.Emit (OpCodes.Ldelema, etype);
8339 ec.EmitArrayStore ((ArrayContainer) type);
8345 for (int j = dims - 1; j >= 0; j--){
8347 if (current_pos [j] < bounds [j])
8349 current_pos [j] = 0;
8353 if (stackArray != null)
8354 stackArray.PrepareCleanup (ec);
8357 public override void Emit (EmitContext ec)
8359 var await_field = EmitToFieldSource (ec);
8360 if (await_field != null)
8361 await_field.Emit (ec);
8364 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8366 if (first_emit != null) {
8367 first_emit.Emit (ec);
8368 first_emit_temp.Store (ec);
8371 StackFieldExpr await_stack_field;
8372 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8373 await_stack_field = ec.GetTemporaryField (type);
8376 await_stack_field = null;
8379 EmitExpressionsList (ec, arguments);
8381 ec.EmitArrayNew ((ArrayContainer) type);
8383 if (initializers == null)
8384 return await_stack_field;
8386 if (await_stack_field != null)
8387 await_stack_field.EmitAssignFromStack (ec);
8391 // Emit static initializer for arrays which contain more than 2 items and
8392 // the static initializer will initialize at least 25% of array values or there
8393 // is more than 10 items to be initialized
8395 // NOTE: const_initializers_count does not contain default constant values.
8397 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8398 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8399 EmitStaticInitializers (ec, await_stack_field);
8401 if (!only_constant_initializers)
8402 EmitDynamicInitializers (ec, false, await_stack_field);
8406 EmitDynamicInitializers (ec, true, await_stack_field);
8409 if (first_emit_temp != null)
8410 first_emit_temp.Release (ec);
8412 return await_stack_field;
8415 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8417 // no multi dimensional or jagged arrays
8418 if (arguments.Count != 1 || array_element_type.IsArray) {
8419 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8423 // No array covariance, except for array -> object
8424 if (type != targetType) {
8425 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8426 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8430 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8431 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8436 // Single dimensional array of 0 size
8437 if (array_data == null) {
8438 IntConstant ic = arguments[0] as IntConstant;
8439 if (ic == null || !ic.IsDefaultValue) {
8440 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8448 enc.Encode (array_data.Count);
8449 foreach (var element in array_data) {
8450 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8454 protected override void CloneTo (CloneContext clonectx, Expression t)
8456 ArrayCreation target = (ArrayCreation) t;
8458 if (requested_base_type != null)
8459 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8461 if (arguments != null){
8462 target.arguments = new List<Expression> (arguments.Count);
8463 foreach (Expression e in arguments)
8464 target.arguments.Add (e.Clone (clonectx));
8467 if (initializers != null)
8468 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8471 public override object Accept (StructuralVisitor visitor)
8473 return visitor.Visit (this);
8478 // Represents an implicitly typed array epxression
8480 class ImplicitlyTypedArrayCreation : ArrayCreation
8482 TypeInferenceContext best_type_inference;
8484 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8485 : base (null, rank, initializers, loc)
8489 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8490 : base (null, initializers, loc)
8494 protected override Expression DoResolve (ResolveContext ec)
8499 dimensions = rank.Dimension;
8501 best_type_inference = new TypeInferenceContext ();
8503 if (!ResolveInitializers (ec))
8506 best_type_inference.FixAllTypes (ec);
8507 array_element_type = best_type_inference.InferredTypeArguments[0];
8508 best_type_inference = null;
8510 if (array_element_type == null ||
8511 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8512 arguments.Count != rank.Dimension) {
8513 ec.Report.Error (826, loc,
8514 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8519 // At this point we found common base type for all initializer elements
8520 // but we have to be sure that all static initializer elements are of
8523 UnifyInitializerElement (ec);
8525 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8526 eclass = ExprClass.Value;
8531 // Converts static initializer only
8533 void UnifyInitializerElement (ResolveContext ec)
8535 for (int i = 0; i < array_data.Count; ++i) {
8536 Expression e = array_data[i];
8538 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8542 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8544 element = element.Resolve (ec);
8545 if (element != null)
8546 best_type_inference.AddCommonTypeBound (element.Type);
8552 sealed class CompilerGeneratedThis : This
8554 public CompilerGeneratedThis (TypeSpec type, Location loc)
8560 protected override Expression DoResolve (ResolveContext rc)
8562 eclass = ExprClass.Variable;
8564 var block = rc.CurrentBlock;
8565 if (block != null) {
8566 var top = block.ParametersBlock.TopBlock;
8567 if (top.ThisVariable != null)
8568 variable_info = top.ThisVariable.VariableInfo;
8575 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8577 return DoResolve (rc);
8580 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8587 /// Represents the `this' construct
8590 public class This : VariableReference
8592 sealed class ThisVariable : ILocalVariable
8594 public static readonly ILocalVariable Instance = new ThisVariable ();
8596 public void Emit (EmitContext ec)
8601 public void EmitAssign (EmitContext ec)
8603 throw new InvalidOperationException ();
8606 public void EmitAddressOf (EmitContext ec)
8612 protected VariableInfo variable_info;
8614 public This (Location loc)
8621 public override string Name {
8622 get { return "this"; }
8625 public override bool IsLockedByStatement {
8633 public override bool IsRef {
8634 get { return type.IsStruct; }
8637 public override bool IsSideEffectFree {
8643 protected override ILocalVariable Variable {
8644 get { return ThisVariable.Instance; }
8647 public override VariableInfo VariableInfo {
8648 get { return variable_info; }
8651 public override bool IsFixed {
8652 get { return false; }
8657 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8660 // It's null for all cases when we don't need to check `this'
8661 // definitive assignment
8663 if (variable_info == null)
8666 if (fc.IsDefinitelyAssigned (variable_info))
8669 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8672 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8674 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8675 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8676 } else if (ec.CurrentAnonymousMethod != null) {
8677 ec.Report.Error (1673, loc,
8678 "Anonymous methods inside structs cannot access instance members of `this'. " +
8679 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8681 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8685 public override void FlowAnalysis (FlowAnalysisContext fc)
8687 CheckStructThisDefiniteAssignment (fc);
8690 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8695 AnonymousMethodStorey storey = ae.Storey;
8696 return storey != null ? storey.HoistedThis : null;
8699 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8701 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8704 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8707 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8713 public virtual void ResolveBase (ResolveContext ec)
8715 eclass = ExprClass.Variable;
8716 type = ec.CurrentType;
8718 if (!IsThisAvailable (ec, false)) {
8719 Error_ThisNotAvailable (ec);
8723 var block = ec.CurrentBlock;
8724 if (block != null) {
8725 var top = block.ParametersBlock.TopBlock;
8726 if (top.ThisVariable != null)
8727 variable_info = top.ThisVariable.VariableInfo;
8729 AnonymousExpression am = ec.CurrentAnonymousMethod;
8730 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8732 // Hoisted this is almost like hoisted variable but not exactly. When
8733 // there is no variable hoisted we can simply emit an instance method
8734 // without lifting this into a storey. Unfotunatelly this complicates
8735 // things in other cases because we don't know where this will be hoisted
8736 // until top-level block is fully resolved
8738 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8739 am.SetHasThisAccess ();
8744 protected override Expression DoResolve (ResolveContext ec)
8750 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8752 if (eclass == ExprClass.Unresolved)
8756 if (right_side == EmptyExpression.UnaryAddress)
8757 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8758 else if (right_side == EmptyExpression.OutAccess)
8759 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8761 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8767 public override int GetHashCode()
8769 throw new NotImplementedException ();
8772 public override bool Equals (object obj)
8774 This t = obj as This;
8781 protected override void CloneTo (CloneContext clonectx, Expression t)
8786 public override void SetHasAddressTaken ()
8791 public override object Accept (StructuralVisitor visitor)
8793 return visitor.Visit (this);
8798 /// Represents the `__arglist' construct
8800 public class ArglistAccess : Expression
8802 public ArglistAccess (Location loc)
8807 protected override void CloneTo (CloneContext clonectx, Expression target)
8812 public override bool ContainsEmitWithAwait ()
8817 public override Expression CreateExpressionTree (ResolveContext ec)
8819 throw new NotSupportedException ("ET");
8822 protected override Expression DoResolve (ResolveContext ec)
8824 eclass = ExprClass.Variable;
8825 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8827 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8828 ec.Report.Error (190, loc,
8829 "The __arglist construct is valid only within a variable argument method");
8835 public override void Emit (EmitContext ec)
8837 ec.Emit (OpCodes.Arglist);
8840 public override object Accept (StructuralVisitor visitor)
8842 return visitor.Visit (this);
8847 /// Represents the `__arglist (....)' construct
8849 public class Arglist : Expression
8851 Arguments arguments;
8853 public Arglist (Location loc)
8858 public Arglist (Arguments args, Location l)
8864 public Arguments Arguments {
8870 public MetaType[] ArgumentTypes {
8872 if (arguments == null)
8873 return MetaType.EmptyTypes;
8875 var retval = new MetaType[arguments.Count];
8876 for (int i = 0; i < retval.Length; i++)
8877 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8883 public override bool ContainsEmitWithAwait ()
8885 throw new NotImplementedException ();
8888 public override Expression CreateExpressionTree (ResolveContext ec)
8890 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8894 protected override Expression DoResolve (ResolveContext ec)
8896 eclass = ExprClass.Variable;
8897 type = InternalType.Arglist;
8898 if (arguments != null) {
8899 bool dynamic; // Can be ignored as there is always only 1 overload
8900 arguments.Resolve (ec, out dynamic);
8906 public override void Emit (EmitContext ec)
8908 if (arguments != null)
8909 arguments.Emit (ec);
8912 protected override void CloneTo (CloneContext clonectx, Expression t)
8914 Arglist target = (Arglist) t;
8916 if (arguments != null)
8917 target.arguments = arguments.Clone (clonectx);
8920 public override object Accept (StructuralVisitor visitor)
8922 return visitor.Visit (this);
8926 public class RefValueExpr : ShimExpression, IAssignMethod
8928 FullNamedExpression texpr;
8930 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8937 public FullNamedExpression TypeExpression {
8943 public override bool ContainsEmitWithAwait ()
8948 protected override Expression DoResolve (ResolveContext rc)
8950 expr = expr.Resolve (rc);
8951 type = texpr.ResolveAsType (rc);
8952 if (expr == null || type == null)
8955 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8956 eclass = ExprClass.Value;
8960 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8962 return DoResolve (rc);
8965 public override void Emit (EmitContext ec)
8968 ec.Emit (OpCodes.Refanyval, type);
8969 ec.EmitLoadFromPtr (type);
8972 public void Emit (EmitContext ec, bool leave_copy)
8974 throw new NotImplementedException ();
8977 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8980 ec.Emit (OpCodes.Refanyval, type);
8983 LocalTemporary temporary = null;
8985 ec.Emit (OpCodes.Dup);
8986 temporary = new LocalTemporary (source.Type);
8987 temporary.Store (ec);
8990 ec.EmitStoreFromPtr (type);
8992 if (temporary != null) {
8993 temporary.Emit (ec);
8994 temporary.Release (ec);
8998 public override object Accept (StructuralVisitor visitor)
9000 return visitor.Visit (this);
9004 public class RefTypeExpr : ShimExpression
9006 public RefTypeExpr (Expression expr, Location loc)
9012 protected override Expression DoResolve (ResolveContext rc)
9014 expr = expr.Resolve (rc);
9018 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9022 type = rc.BuiltinTypes.Type;
9023 eclass = ExprClass.Value;
9027 public override void Emit (EmitContext ec)
9030 ec.Emit (OpCodes.Refanytype);
9031 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9033 ec.Emit (OpCodes.Call, m);
9036 public override object Accept (StructuralVisitor visitor)
9038 return visitor.Visit (this);
9042 public class MakeRefExpr : ShimExpression
9044 public MakeRefExpr (Expression expr, Location loc)
9050 public override bool ContainsEmitWithAwait ()
9052 throw new NotImplementedException ();
9055 protected override Expression DoResolve (ResolveContext rc)
9057 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9058 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9059 eclass = ExprClass.Value;
9063 public override void Emit (EmitContext ec)
9065 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9066 ec.Emit (OpCodes.Mkrefany, expr.Type);
9069 public override object Accept (StructuralVisitor visitor)
9071 return visitor.Visit (this);
9076 /// Implements the typeof operator
9078 public class TypeOf : Expression {
9079 FullNamedExpression QueriedType;
9082 public TypeOf (FullNamedExpression queried_type, Location l)
9084 QueriedType = queried_type;
9089 // Use this constructor for any compiler generated typeof expression
9091 public TypeOf (TypeSpec type, Location loc)
9093 this.typearg = type;
9099 public override bool IsSideEffectFree {
9105 public TypeSpec TypeArgument {
9111 public FullNamedExpression TypeExpression {
9120 protected override void CloneTo (CloneContext clonectx, Expression t)
9122 TypeOf target = (TypeOf) t;
9123 if (QueriedType != null)
9124 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9127 public override bool ContainsEmitWithAwait ()
9132 public override Expression CreateExpressionTree (ResolveContext ec)
9134 Arguments args = new Arguments (2);
9135 args.Add (new Argument (this));
9136 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9137 return CreateExpressionFactoryCall (ec, "Constant", args);
9140 protected override Expression DoResolve (ResolveContext ec)
9142 if (eclass != ExprClass.Unresolved)
9145 if (typearg == null) {
9147 // Pointer types are allowed without explicit unsafe, they are just tokens
9149 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9150 typearg = QueriedType.ResolveAsType (ec, true);
9153 if (typearg == null)
9156 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9157 ec.Report.Error (1962, QueriedType.Location,
9158 "The typeof operator cannot be used on the dynamic type");
9162 type = ec.BuiltinTypes.Type;
9164 // Even though what is returned is a type object, it's treated as a value by the compiler.
9165 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9166 eclass = ExprClass.Value;
9170 static bool ContainsDynamicType (TypeSpec type)
9172 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9175 var element_container = type as ElementTypeSpec;
9176 if (element_container != null)
9177 return ContainsDynamicType (element_container.Element);
9179 foreach (var t in type.TypeArguments) {
9180 if (ContainsDynamicType (t)) {
9188 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9190 // Target type is not System.Type therefore must be object
9191 // and we need to use different encoding sequence
9192 if (targetType != type)
9195 if (typearg is InflatedTypeSpec) {
9198 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9199 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9200 typearg.GetSignatureForError ());
9204 gt = gt.DeclaringType;
9205 } while (gt != null);
9208 if (ContainsDynamicType (typearg)) {
9209 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9213 enc.EncodeTypeName (typearg);
9216 public override void Emit (EmitContext ec)
9218 ec.Emit (OpCodes.Ldtoken, typearg);
9219 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9221 ec.Emit (OpCodes.Call, m);
9224 public override object Accept (StructuralVisitor visitor)
9226 return visitor.Visit (this);
9230 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9232 public TypeOfMethod (MethodSpec method, Location loc)
9233 : base (method, loc)
9237 protected override Expression DoResolve (ResolveContext ec)
9239 if (member.IsConstructor) {
9240 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9242 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9248 return base.DoResolve (ec);
9251 public override void Emit (EmitContext ec)
9253 ec.Emit (OpCodes.Ldtoken, member);
9256 ec.Emit (OpCodes.Castclass, type);
9259 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9261 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9264 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9266 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9270 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9272 protected readonly T member;
9274 protected TypeOfMember (T member, Location loc)
9276 this.member = member;
9280 public override bool IsSideEffectFree {
9286 public override bool ContainsEmitWithAwait ()
9291 public override Expression CreateExpressionTree (ResolveContext ec)
9293 Arguments args = new Arguments (2);
9294 args.Add (new Argument (this));
9295 args.Add (new Argument (new TypeOf (type, loc)));
9296 return CreateExpressionFactoryCall (ec, "Constant", args);
9299 protected override Expression DoResolve (ResolveContext ec)
9301 eclass = ExprClass.Value;
9305 public override void Emit (EmitContext ec)
9307 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9308 PredefinedMember<MethodSpec> p;
9310 p = GetTypeFromHandleGeneric (ec);
9311 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9313 p = GetTypeFromHandle (ec);
9316 var mi = p.Resolve (loc);
9318 ec.Emit (OpCodes.Call, mi);
9321 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9322 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9325 sealed class TypeOfField : TypeOfMember<FieldSpec>
9327 public TypeOfField (FieldSpec field, Location loc)
9332 protected override Expression DoResolve (ResolveContext ec)
9334 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9338 return base.DoResolve (ec);
9341 public override void Emit (EmitContext ec)
9343 ec.Emit (OpCodes.Ldtoken, member);
9347 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9349 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9352 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9354 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9359 /// Implements the sizeof expression
9361 public class SizeOf : Expression {
9362 readonly Expression texpr;
9363 TypeSpec type_queried;
9365 public SizeOf (Expression queried_type, Location l)
9367 this.texpr = queried_type;
9371 public override bool IsSideEffectFree {
9377 public Expression TypeExpression {
9383 public override bool ContainsEmitWithAwait ()
9388 public override Expression CreateExpressionTree (ResolveContext ec)
9390 Error_PointerInsideExpressionTree (ec);
9394 protected override Expression DoResolve (ResolveContext ec)
9396 type_queried = texpr.ResolveAsType (ec);
9397 if (type_queried == null)
9400 if (type_queried.IsEnum)
9401 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9403 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9405 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9408 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9413 ec.Report.Error (233, loc,
9414 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9415 type_queried.GetSignatureForError ());
9418 type = ec.BuiltinTypes.Int;
9419 eclass = ExprClass.Value;
9423 public override void Emit (EmitContext ec)
9425 ec.Emit (OpCodes.Sizeof, type_queried);
9428 protected override void CloneTo (CloneContext clonectx, Expression t)
9432 public override object Accept (StructuralVisitor visitor)
9434 return visitor.Visit (this);
9439 /// Implements the qualified-alias-member (::) expression.
9441 public class QualifiedAliasMember : MemberAccess
9443 readonly string alias;
9444 public static readonly string GlobalAlias = "global";
9446 public QualifiedAliasMember (string alias, string identifier, Location l)
9447 : base (null, identifier, l)
9452 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9453 : base (null, identifier, targs, l)
9458 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9459 : base (null, identifier, arity, l)
9464 public string Alias {
9470 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9472 if (alias == GlobalAlias)
9473 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9475 int errors = mc.Module.Compiler.Report.Errors;
9476 var expr = mc.LookupNamespaceAlias (alias);
9478 if (errors == mc.Module.Compiler.Report.Errors)
9479 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9487 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9489 expr = CreateExpressionFromAlias (mc);
9493 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9496 protected override Expression DoResolve (ResolveContext rc)
9498 return ResolveAsTypeOrNamespace (rc, false);
9501 public override string GetSignatureForError ()
9504 if (targs != null) {
9505 name = Name + "<" + targs.GetSignatureForError () + ">";
9508 return alias + "::" + name;
9511 public override bool HasConditionalAccess ()
9516 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9518 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9519 rc.Module.Compiler.Report.Error (687, loc,
9520 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9521 GetSignatureForError ());
9526 return DoResolve (rc);
9529 protected override void CloneTo (CloneContext clonectx, Expression t)
9534 public override object Accept (StructuralVisitor visitor)
9536 return visitor.Visit (this);
9541 /// Implements the member access expression
9543 public class MemberAccess : ATypeNameExpression
9545 protected Expression expr;
9547 public MemberAccess (Expression expr, string id)
9548 : base (id, expr.Location)
9553 public MemberAccess (Expression expr, string identifier, Location loc)
9554 : base (identifier, loc)
9559 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9560 : base (identifier, args, loc)
9565 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9566 : base (identifier, arity, loc)
9571 public Expression LeftExpression {
9577 public override Location StartLocation {
9579 return expr == null ? loc : expr.StartLocation;
9583 protected override Expression DoResolve (ResolveContext rc)
9585 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9587 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9592 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9594 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9596 if (e is TypeExpr) {
9597 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9602 e = e.ResolveLValue (rc, rhs);
9607 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9609 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9610 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9612 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9615 public override bool HasConditionalAccess ()
9617 return LeftExpression.HasConditionalAccess ();
9620 public static bool IsValidDotExpression (TypeSpec type)
9622 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9623 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9625 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9628 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9630 var sn = expr as SimpleName;
9631 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9634 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9637 // Resolve expression which does have type set as we need expression type
9638 // with disable flow analysis as we don't know whether left side expression
9639 // is used as variable or type
9641 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9642 expr = expr.Resolve (rc);
9643 } else if (expr is TypeParameterExpr) {
9644 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9648 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9649 expr = expr.Resolve (rc, flags);
9656 var ns = expr as NamespaceExpression;
9658 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9660 if (retval == null) {
9661 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
9665 if (HasTypeArguments)
9666 return new GenericTypeExpr (retval.Type, targs, loc);
9672 TypeSpec expr_type = expr.Type;
9673 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9674 me = expr as MemberExpr;
9676 me.ResolveInstanceExpression (rc, null);
9678 Arguments args = new Arguments (1);
9679 args.Add (new Argument (expr));
9680 return new DynamicMemberBinder (Name, args, loc);
9683 var cma = this as ConditionalMemberAccess;
9685 if (!IsNullPropagatingValid (expr.Type)) {
9686 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9690 if (expr_type.IsNullableType) {
9691 expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
9692 expr_type = expr.Type;
9696 if (!IsValidDotExpression (expr_type)) {
9697 Error_OperatorCannotBeApplied (rc, expr_type);
9701 var lookup_arity = Arity;
9702 bool errorMode = false;
9703 Expression member_lookup;
9705 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9706 if (member_lookup == null) {
9708 // Try to look for extension method when member lookup failed
9710 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9711 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
9712 if (methods != null) {
9713 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9714 if (HasTypeArguments) {
9715 if (!targs.Resolve (rc))
9718 emg.SetTypeArguments (rc, targs);
9722 emg.ConditionalAccess = true;
9724 // TODO: it should really skip the checks bellow
9725 return emg.Resolve (rc);
9731 if (member_lookup == null) {
9732 var dep = expr_type.GetMissingDependencies ();
9734 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9735 } else if (expr is TypeExpr) {
9736 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9738 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9744 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9745 // Leave it to overload resolution to report correct error
9746 } else if (!(member_lookup is TypeExpr)) {
9747 // TODO: rc.SymbolRelatedToPreviousError
9748 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9753 if (member_lookup != null)
9757 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9761 TypeExpr texpr = member_lookup as TypeExpr;
9762 if (texpr != null) {
9763 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9764 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9765 Name, texpr.GetSignatureForError ());
9768 if (!texpr.Type.IsAccessible (rc)) {
9769 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9770 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9774 if (HasTypeArguments) {
9775 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9778 return member_lookup;
9781 me = member_lookup as MemberExpr;
9783 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9788 me.ConditionalAccess = true;
9791 me = me.ResolveMemberAccess (rc, expr, sn);
9794 if (!targs.Resolve (rc))
9797 me.SetTypeArguments (rc, targs);
9803 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9805 FullNamedExpression fexpr = expr as FullNamedExpression;
9806 if (fexpr == null) {
9807 expr.ResolveAsType (rc);
9811 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9813 if (expr_resolved == null)
9816 var ns = expr_resolved as NamespaceExpression;
9818 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9820 if (retval == null) {
9821 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
9822 } else if (Arity > 0) {
9823 if (HasTypeArguments) {
9824 retval = new GenericTypeExpr (retval.Type, targs, loc);
9825 if (retval.ResolveAsType (rc) == null)
9828 if (!allowUnboundTypeArguments)
9829 Error_OpenGenericTypeIsNotAllowed (rc);
9831 retval = new GenericOpenTypeExpr (retval.Type, loc);
9838 var tnew_expr = expr_resolved.ResolveAsType (rc);
9839 if (tnew_expr == null)
9842 TypeSpec expr_type = tnew_expr;
9843 if (TypeManager.IsGenericParameter (expr_type)) {
9844 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9845 tnew_expr.GetSignatureForError ());
9849 var qam = this as QualifiedAliasMember;
9851 rc.Module.Compiler.Report.Error (431, loc,
9852 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9857 TypeSpec nested = null;
9858 while (expr_type != null) {
9859 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9860 if (nested == null) {
9861 if (expr_type == tnew_expr) {
9862 Error_IdentifierNotFound (rc, expr_type);
9866 expr_type = tnew_expr;
9867 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9868 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9872 if (nested.IsAccessible (rc))
9876 // Keep looking after inaccessible candidate but only if
9877 // we are not in same context as the definition itself
9879 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9882 expr_type = expr_type.BaseType;
9887 if (HasTypeArguments) {
9888 texpr = new GenericTypeExpr (nested, targs, loc);
9890 if (!allowUnboundTypeArguments || expr_resolved is GenericTypeExpr) // && HasTypeArguments
9891 Error_OpenGenericTypeIsNotAllowed (rc);
9893 texpr = new GenericOpenTypeExpr (nested, loc);
9895 } else if (expr_resolved is GenericOpenTypeExpr) {
9896 texpr = new GenericOpenTypeExpr (nested, loc);
9898 texpr = new TypeExpression (nested, loc);
9901 if (texpr.ResolveAsType (rc) == null)
9907 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9909 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9911 if (nested != null) {
9912 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9916 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9917 if (any_other_member != null) {
9918 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9922 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9923 Name, expr_type.GetSignatureForError ());
9926 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9928 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9931 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9933 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9934 ec.Report.SymbolRelatedToPreviousError (type);
9936 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9938 // a using directive or an assembly reference
9940 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9942 missing = "an assembly reference";
9945 ec.Report.Error (1061, loc,
9946 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9947 type.GetSignatureForError (), name, missing);
9951 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9954 public override string GetSignatureForError ()
9956 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9959 protected override void CloneTo (CloneContext clonectx, Expression t)
9961 MemberAccess target = (MemberAccess) t;
9963 target.expr = expr.Clone (clonectx);
9966 public override object Accept (StructuralVisitor visitor)
9968 return visitor.Visit (this);
9972 public class ConditionalMemberAccess : MemberAccess
9974 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9975 : base (expr, identifier, args, loc)
9979 public override bool HasConditionalAccess ()
9986 /// Implements checked expressions
9988 public class CheckedExpr : Expression {
9990 public Expression Expr;
9992 public CheckedExpr (Expression e, Location l)
9998 public override bool ContainsEmitWithAwait ()
10000 return Expr.ContainsEmitWithAwait ();
10003 public override Expression CreateExpressionTree (ResolveContext ec)
10005 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10006 return Expr.CreateExpressionTree (ec);
10009 protected override Expression DoResolve (ResolveContext ec)
10011 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10012 Expr = Expr.Resolve (ec);
10017 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10020 eclass = Expr.eclass;
10025 public override void Emit (EmitContext ec)
10027 using (ec.With (EmitContext.Options.CheckedScope, true))
10031 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10033 using (ec.With (EmitContext.Options.CheckedScope, true))
10034 Expr.EmitBranchable (ec, target, on_true);
10037 public override void FlowAnalysis (FlowAnalysisContext fc)
10039 Expr.FlowAnalysis (fc);
10042 public override SLE.Expression MakeExpression (BuilderContext ctx)
10044 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10045 return Expr.MakeExpression (ctx);
10049 protected override void CloneTo (CloneContext clonectx, Expression t)
10051 CheckedExpr target = (CheckedExpr) t;
10053 target.Expr = Expr.Clone (clonectx);
10056 public override object Accept (StructuralVisitor visitor)
10058 return visitor.Visit (this);
10063 /// Implements the unchecked expression
10065 public class UnCheckedExpr : Expression {
10067 public Expression Expr;
10069 public UnCheckedExpr (Expression e, Location l)
10075 public override bool ContainsEmitWithAwait ()
10077 return Expr.ContainsEmitWithAwait ();
10080 public override Expression CreateExpressionTree (ResolveContext ec)
10082 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10083 return Expr.CreateExpressionTree (ec);
10086 protected override Expression DoResolve (ResolveContext ec)
10088 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10089 Expr = Expr.Resolve (ec);
10094 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10097 eclass = Expr.eclass;
10102 public override void Emit (EmitContext ec)
10104 using (ec.With (EmitContext.Options.CheckedScope, false))
10108 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10110 using (ec.With (EmitContext.Options.CheckedScope, false))
10111 Expr.EmitBranchable (ec, target, on_true);
10114 public override void FlowAnalysis (FlowAnalysisContext fc)
10116 Expr.FlowAnalysis (fc);
10119 protected override void CloneTo (CloneContext clonectx, Expression t)
10121 UnCheckedExpr target = (UnCheckedExpr) t;
10123 target.Expr = Expr.Clone (clonectx);
10126 public override object Accept (StructuralVisitor visitor)
10128 return visitor.Visit (this);
10133 /// An Element Access expression.
10135 /// During semantic analysis these are transformed into
10136 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10138 public class ElementAccess : Expression
10140 public Arguments Arguments;
10141 public Expression Expr;
10143 public ElementAccess (Expression e, Arguments args, Location loc)
10147 this.Arguments = args;
10150 public bool ConditionalAccess { get; set; }
10152 public override Location StartLocation {
10154 return Expr.StartLocation;
10158 public override bool ContainsEmitWithAwait ()
10160 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10164 // We perform some simple tests, and then to "split" the emit and store
10165 // code we create an instance of a different class, and return that.
10167 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10169 Expr = Expr.Resolve (ec);
10175 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10176 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10181 return new ArrayAccess (this, loc) {
10182 ConditionalAccess = ConditionalAccess,
10183 ConditionalAccessReceiver = conditionalAccessReceiver
10186 if (type.IsPointer)
10187 return MakePointerAccess (ec, type);
10189 FieldExpr fe = Expr as FieldExpr;
10191 var ff = fe.Spec as FixedFieldSpec;
10193 return MakePointerAccess (ec, ff.ElementType);
10197 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10198 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10199 var indexer = new IndexerExpr (indexers, type, this) {
10200 ConditionalAccess = ConditionalAccess
10203 if (conditionalAccessReceiver)
10204 indexer.SetConditionalAccessReceiver ();
10209 Error_CannotApplyIndexing (ec, type, loc);
10214 public override Expression CreateExpressionTree (ResolveContext ec)
10216 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10217 Expr.CreateExpressionTree (ec));
10219 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10222 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10224 if (type != InternalType.ErrorType) {
10225 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10226 type.GetSignatureForError ());
10230 public override bool HasConditionalAccess ()
10232 return ConditionalAccess || Expr.HasConditionalAccess ();
10235 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
10237 if (Arguments.Count != 1){
10238 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
10242 var arg = Arguments[0];
10243 if (arg is NamedArgument)
10244 Error_NamedArgument ((NamedArgument) arg, rc.Report);
10246 var index = arg.Expr.Resolve (rc);
10250 index = ConvertExpressionToArrayIndex (rc, index, true);
10252 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
10253 return new Indirection (p, loc);
10256 protected override Expression DoResolve (ResolveContext rc)
10259 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10260 if (HasConditionalAccess ()) {
10261 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10262 expr = CreateAccessExpression (rc, true);
10266 return expr.Resolve (rc);
10271 expr = CreateAccessExpression (rc, false);
10275 return expr.Resolve (rc);
10278 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10280 var res = CreateAccessExpression (ec, false);
10284 return res.ResolveLValue (ec, rhs);
10287 public override void Emit (EmitContext ec)
10289 throw new Exception ("Should never be reached");
10292 public static void Error_NamedArgument (NamedArgument na, Report Report)
10294 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
10297 public override void FlowAnalysis (FlowAnalysisContext fc)
10299 Expr.FlowAnalysis (fc);
10301 if (ConditionalAccess)
10302 fc.BranchConditionalAccessDefiniteAssignment ();
10304 Arguments.FlowAnalysis (fc);
10307 public override string GetSignatureForError ()
10309 return Expr.GetSignatureForError ();
10312 protected override void CloneTo (CloneContext clonectx, Expression t)
10314 ElementAccess target = (ElementAccess) t;
10316 target.Expr = Expr.Clone (clonectx);
10317 if (Arguments != null)
10318 target.Arguments = Arguments.Clone (clonectx);
10321 public override object Accept (StructuralVisitor visitor)
10323 return visitor.Visit (this);
10328 /// Implements array access
10330 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10332 // Points to our "data" repository
10336 LocalTemporary temp;
10338 bool? has_await_args;
10340 public ArrayAccess (ElementAccess ea_data, Location l)
10346 public bool ConditionalAccess { get; set; }
10348 public bool ConditionalAccessReceiver { get; set; }
10350 public void AddressOf (EmitContext ec, AddressOp mode)
10352 var ac = (ArrayContainer) ea.Expr.Type;
10354 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10355 LoadInstanceAndArguments (ec, false, true);
10358 LoadInstanceAndArguments (ec, false, false);
10360 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10361 ec.Emit (OpCodes.Readonly);
10363 ec.EmitArrayAddress (ac);
10366 public override Expression CreateExpressionTree (ResolveContext ec)
10368 if (ConditionalAccess)
10369 Error_NullShortCircuitInsideExpressionTree (ec);
10371 return ea.CreateExpressionTree (ec);
10374 public override bool ContainsEmitWithAwait ()
10376 return ea.ContainsEmitWithAwait ();
10379 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10381 if (ConditionalAccess)
10382 throw new NotSupportedException ("null propagating operator assignment");
10384 return DoResolve (ec);
10387 protected override Expression DoResolve (ResolveContext ec)
10389 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10391 ea.Arguments.Resolve (ec, out dynamic);
10393 var ac = ea.Expr.Type as ArrayContainer;
10394 int rank = ea.Arguments.Count;
10395 if (ac.Rank != rank) {
10396 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10397 rank.ToString (), ac.Rank.ToString ());
10402 if (type.IsPointer && !ec.IsUnsafe) {
10403 UnsafeError (ec, ea.Location);
10406 if (ConditionalAccessReceiver)
10407 type = LiftMemberType (ec, type);
10409 foreach (Argument a in ea.Arguments) {
10410 var na = a as NamedArgument;
10412 ElementAccess.Error_NamedArgument (na, ec.Report);
10414 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10417 eclass = ExprClass.Variable;
10422 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10424 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10427 public override void FlowAnalysis (FlowAnalysisContext fc)
10429 ea.FlowAnalysis (fc);
10433 // Load the array arguments into the stack.
10435 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10437 if (prepareAwait) {
10438 ea.Expr = ea.Expr.EmitToField (ec);
10440 var ie = new InstanceEmitter (ea.Expr, false);
10441 ie.Emit (ec, ConditionalAccess);
10443 if (duplicateArguments) {
10444 ec.Emit (OpCodes.Dup);
10446 var copy = new LocalTemporary (ea.Expr.Type);
10452 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10453 if (dup_args != null)
10454 ea.Arguments = dup_args;
10457 public void Emit (EmitContext ec, bool leave_copy)
10460 ec.EmitLoadFromPtr (type);
10462 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10463 LoadInstanceAndArguments (ec, false, true);
10466 if (ConditionalAccessReceiver)
10467 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10469 var ac = (ArrayContainer) ea.Expr.Type;
10470 LoadInstanceAndArguments (ec, false, false);
10471 ec.EmitArrayLoad (ac);
10473 if (ConditionalAccessReceiver)
10474 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10478 ec.Emit (OpCodes.Dup);
10479 temp = new LocalTemporary (this.type);
10484 public override void Emit (EmitContext ec)
10489 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10491 var ac = (ArrayContainer) ea.Expr.Type;
10492 TypeSpec t = source.Type;
10494 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10497 // When we are dealing with a struct, get the address of it to avoid value copy
10498 // Same cannot be done for reference type because array covariance and the
10499 // check in ldelema requires to specify the type of array element stored at the index
10501 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10502 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10504 if (has_await_args.Value) {
10505 if (source.ContainsEmitWithAwait ()) {
10506 source = source.EmitToField (ec);
10507 isCompound = false;
10511 LoadInstanceAndArguments (ec, isCompound, false);
10516 ec.EmitArrayAddress (ac);
10519 ec.Emit (OpCodes.Dup);
10523 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10525 if (has_await_args.Value) {
10526 if (source.ContainsEmitWithAwait ())
10527 source = source.EmitToField (ec);
10529 LoadInstanceAndArguments (ec, false, false);
10536 var lt = ea.Expr as LocalTemporary;
10542 ec.Emit (OpCodes.Dup);
10543 temp = new LocalTemporary (this.type);
10548 ec.EmitStoreFromPtr (t);
10550 ec.EmitArrayStore (ac);
10553 if (temp != null) {
10559 public override Expression EmitToField (EmitContext ec)
10562 // Have to be specialized for arrays to get access to
10563 // underlying element. Instead of another result copy we
10564 // need direct access to element
10568 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10570 ea.Expr = ea.Expr.EmitToField (ec);
10571 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10575 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10577 #if NET_4_0 || MOBILE_DYNAMIC
10578 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10580 throw new NotImplementedException ();
10584 public override SLE.Expression MakeExpression (BuilderContext ctx)
10586 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10589 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10591 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10592 return Arguments.MakeExpression (ea.Arguments, ctx);
10598 // Indexer access expression
10600 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10602 IList<MemberSpec> indexers;
10603 Arguments arguments;
10604 TypeSpec queried_type;
10606 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10607 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10611 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10614 this.indexers = indexers;
10615 this.queried_type = queriedType;
10616 this.InstanceExpression = instance;
10617 this.arguments = args;
10622 protected override Arguments Arguments {
10631 protected override TypeSpec DeclaringType {
10633 return best_candidate.DeclaringType;
10637 public override bool IsInstance {
10643 public override bool IsStatic {
10649 public override string KindName {
10650 get { return "indexer"; }
10653 public override string Name {
10661 public override bool ContainsEmitWithAwait ()
10663 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10666 public override Expression CreateExpressionTree (ResolveContext ec)
10668 if (ConditionalAccess) {
10669 Error_NullShortCircuitInsideExpressionTree (ec);
10672 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10673 InstanceExpression.CreateExpressionTree (ec),
10674 new TypeOfMethod (Getter, loc));
10676 return CreateExpressionFactoryCall (ec, "Call", args);
10679 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10681 LocalTemporary await_source_arg = null;
10684 emitting_compound_assignment = true;
10685 if (source is DynamicExpressionStatement) {
10690 emitting_compound_assignment = false;
10692 if (has_await_arguments) {
10693 await_source_arg = new LocalTemporary (Type);
10694 await_source_arg.Store (ec);
10696 arguments.Add (new Argument (await_source_arg));
10699 temp = await_source_arg;
10702 has_await_arguments = false;
10707 ec.Emit (OpCodes.Dup);
10708 temp = new LocalTemporary (Type);
10714 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10715 source = source.EmitToField (ec);
10717 temp = new LocalTemporary (Type);
10724 arguments.Add (new Argument (source));
10727 var call = new CallEmitter ();
10728 call.InstanceExpression = InstanceExpression;
10729 if (arguments == null)
10730 call.InstanceExpressionOnStack = true;
10732 call.Emit (ec, Setter, arguments, loc);
10734 if (temp != null) {
10737 } else if (leave_copy) {
10741 if (await_source_arg != null) {
10742 await_source_arg.Release (ec);
10746 public override void FlowAnalysis (FlowAnalysisContext fc)
10748 base.FlowAnalysis (fc);
10749 arguments.FlowAnalysis (fc);
10751 if (conditional_access_receiver)
10752 fc.ConditionalAccessEnd ();
10755 public override string GetSignatureForError ()
10757 return best_candidate.GetSignatureForError ();
10760 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10763 throw new NotSupportedException ();
10765 var value = new[] { source.MakeExpression (ctx) };
10766 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10767 #if NET_4_0 || MOBILE_DYNAMIC
10768 return SLE.Expression.Block (
10769 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10772 return args.First ();
10777 public override SLE.Expression MakeExpression (BuilderContext ctx)
10780 return base.MakeExpression (ctx);
10782 var args = Arguments.MakeExpression (arguments, ctx);
10783 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10787 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10789 if (best_candidate != null)
10792 eclass = ExprClass.IndexerAccess;
10795 arguments.Resolve (rc, out dynamic);
10797 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10800 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10801 res.BaseMembersProvider = this;
10802 res.InstanceQualifier = this;
10804 // TODO: Do I need 2 argument sets?
10805 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10806 if (best_candidate != null)
10807 type = res.BestCandidateReturnType;
10808 else if (!res.BestCandidateIsDynamic)
10813 // It has dynamic arguments
10816 Arguments args = new Arguments (arguments.Count + 1);
10818 rc.Report.Error (1972, loc,
10819 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10821 args.Add (new Argument (InstanceExpression));
10823 args.AddRange (arguments);
10825 best_candidate = null;
10826 return new DynamicIndexBinder (args, loc);
10830 // Try to avoid resolving left expression again
10832 if (right_side != null)
10833 ResolveInstanceExpression (rc, right_side);
10838 protected override void CloneTo (CloneContext clonectx, Expression t)
10840 IndexerExpr target = (IndexerExpr) t;
10842 if (arguments != null)
10843 target.arguments = arguments.Clone (clonectx);
10846 public void SetConditionalAccessReceiver ()
10848 conditional_access_receiver = true;
10851 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10853 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10856 #region IBaseMembersProvider Members
10858 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10860 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10863 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10865 if (queried_type == member.DeclaringType)
10868 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10869 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10872 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10881 // A base access expression
10883 public class BaseThis : This
10885 public BaseThis (Location loc)
10890 public BaseThis (TypeSpec type, Location loc)
10894 eclass = ExprClass.Variable;
10899 public override string Name {
10907 public override Expression CreateExpressionTree (ResolveContext ec)
10909 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10910 return base.CreateExpressionTree (ec);
10913 public override void Emit (EmitContext ec)
10917 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10918 var context_type = ec.CurrentType;
10919 ec.Emit (OpCodes.Ldobj, context_type);
10920 ec.Emit (OpCodes.Box, context_type);
10924 protected override void Error_ThisNotAvailable (ResolveContext ec)
10927 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10929 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10933 public override void ResolveBase (ResolveContext ec)
10935 base.ResolveBase (ec);
10936 type = ec.CurrentType.BaseType;
10939 public override object Accept (StructuralVisitor visitor)
10941 return visitor.Visit (this);
10946 /// This class exists solely to pass the Type around and to be a dummy
10947 /// that can be passed to the conversion functions (this is used by
10948 /// foreach implementation to typecast the object return value from
10949 /// get_Current into the proper type. All code has been generated and
10950 /// we only care about the side effect conversions to be performed
10952 /// This is also now used as a placeholder where a no-action expression
10953 /// is needed (the `New' class).
10955 public class EmptyExpression : Expression
10957 sealed class OutAccessExpression : EmptyExpression
10959 public OutAccessExpression (TypeSpec t)
10964 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10966 rc.Report.Error (206, right_side.Location,
10967 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10973 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10974 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10975 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10976 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10977 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10978 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10979 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10980 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10982 public EmptyExpression (TypeSpec t)
10985 eclass = ExprClass.Value;
10986 loc = Location.Null;
10989 protected override void CloneTo (CloneContext clonectx, Expression target)
10993 public override bool ContainsEmitWithAwait ()
10998 public override Expression CreateExpressionTree (ResolveContext ec)
11000 throw new NotSupportedException ("ET");
11003 protected override Expression DoResolve (ResolveContext ec)
11008 public override void Emit (EmitContext ec)
11010 // nothing, as we only exist to not do anything.
11013 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11017 public override void EmitSideEffect (EmitContext ec)
11021 public override object Accept (StructuralVisitor visitor)
11023 return visitor.Visit (this);
11027 sealed class EmptyAwaitExpression : EmptyExpression
11029 public EmptyAwaitExpression (TypeSpec type)
11034 public override bool ContainsEmitWithAwait ()
11041 // Empty statement expression
11043 public sealed class EmptyExpressionStatement : ExpressionStatement
11045 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11047 private EmptyExpressionStatement ()
11049 loc = Location.Null;
11052 public override bool ContainsEmitWithAwait ()
11057 public override Expression CreateExpressionTree (ResolveContext ec)
11062 public override void EmitStatement (EmitContext ec)
11067 protected override Expression DoResolve (ResolveContext ec)
11069 eclass = ExprClass.Value;
11070 type = ec.BuiltinTypes.Object;
11074 public override void Emit (EmitContext ec)
11079 public override object Accept (StructuralVisitor visitor)
11081 return visitor.Visit (this);
11085 public class ErrorExpression : EmptyExpression
11087 public static readonly ErrorExpression Instance = new ErrorExpression ();
11089 private ErrorExpression ()
11090 : base (InternalType.ErrorType)
11094 public override Expression CreateExpressionTree (ResolveContext ec)
11099 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11104 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11108 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11112 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11116 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11120 public override object Accept (StructuralVisitor visitor)
11122 return visitor.Visit (this);
11126 public class UserCast : Expression {
11130 public UserCast (MethodSpec method, Expression source, Location l)
11132 if (source == null)
11133 throw new ArgumentNullException ("source");
11135 this.method = method;
11136 this.source = source;
11137 type = method.ReturnType;
11141 public Expression Source {
11150 public override bool ContainsEmitWithAwait ()
11152 return source.ContainsEmitWithAwait ();
11155 public override Expression CreateExpressionTree (ResolveContext ec)
11157 Arguments args = new Arguments (3);
11158 args.Add (new Argument (source.CreateExpressionTree (ec)));
11159 args.Add (new Argument (new TypeOf (type, loc)));
11160 args.Add (new Argument (new TypeOfMethod (method, loc)));
11161 return CreateExpressionFactoryCall (ec, "Convert", args);
11164 protected override Expression DoResolve (ResolveContext ec)
11166 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11168 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11170 eclass = ExprClass.Value;
11174 public override void Emit (EmitContext ec)
11177 ec.MarkCallEntry (loc);
11178 ec.Emit (OpCodes.Call, method);
11181 public override void FlowAnalysis (FlowAnalysisContext fc)
11183 source.FlowAnalysis (fc);
11186 public override string GetSignatureForError ()
11188 return TypeManager.CSharpSignature (method);
11191 public override SLE.Expression MakeExpression (BuilderContext ctx)
11194 return base.MakeExpression (ctx);
11196 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11202 // Holds additional type specifiers like ?, *, []
11204 public class ComposedTypeSpecifier
11206 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11208 public readonly int Dimension;
11209 public readonly Location Location;
11211 public ComposedTypeSpecifier (int specifier, Location loc)
11213 this.Dimension = specifier;
11214 this.Location = loc;
11218 public bool IsNullable {
11220 return Dimension == -1;
11224 public bool IsPointer {
11226 return Dimension == -2;
11230 public ComposedTypeSpecifier Next { get; set; }
11234 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11236 return new ComposedTypeSpecifier (dimension, loc);
11239 public static ComposedTypeSpecifier CreateNullable (Location loc)
11241 return new ComposedTypeSpecifier (-1, loc);
11244 public static ComposedTypeSpecifier CreatePointer (Location loc)
11246 return new ComposedTypeSpecifier (-2, loc);
11249 public string GetSignatureForError ()
11254 ArrayContainer.GetPostfixSignature (Dimension);
11256 return Next != null ? s + Next.GetSignatureForError () : s;
11261 // This class is used to "construct" the type during a typecast
11262 // operation. Since the Type.GetType class in .NET can parse
11263 // the type specification, we just use this to construct the type
11264 // one bit at a time.
11266 public class ComposedCast : TypeExpr {
11267 FullNamedExpression left;
11268 ComposedTypeSpecifier spec;
11270 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11273 throw new ArgumentNullException ("spec");
11277 this.loc = left.Location;
11280 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11282 type = left.ResolveAsType (ec);
11286 eclass = ExprClass.Type;
11288 var single_spec = spec;
11290 if (single_spec.IsNullable) {
11291 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11295 single_spec = single_spec.Next;
11296 } else if (single_spec.IsPointer) {
11297 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11300 if (!ec.IsUnsafe) {
11301 UnsafeError (ec.Module.Compiler.Report, loc);
11305 type = PointerContainer.MakeType (ec.Module, type);
11306 single_spec = single_spec.Next;
11307 } while (single_spec != null && single_spec.IsPointer);
11310 if (single_spec != null && single_spec.Dimension > 0) {
11311 if (type.IsSpecialRuntimeType) {
11312 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11313 } else if (type.IsStatic) {
11314 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11315 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11316 type.GetSignatureForError ());
11318 MakeArray (ec.Module, single_spec);
11325 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11327 if (spec.Next != null)
11328 MakeArray (module, spec.Next);
11330 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11333 public override string GetSignatureForError ()
11335 return left.GetSignatureForError () + spec.GetSignatureForError ();
11338 public override object Accept (StructuralVisitor visitor)
11340 return visitor.Visit (this);
11344 class FixedBufferPtr : Expression
11346 readonly Expression array;
11348 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11350 this.type = array_type;
11351 this.array = array;
11355 public override bool ContainsEmitWithAwait ()
11357 throw new NotImplementedException ();
11360 public override Expression CreateExpressionTree (ResolveContext ec)
11362 Error_PointerInsideExpressionTree (ec);
11366 public override void Emit(EmitContext ec)
11371 protected override Expression DoResolve (ResolveContext ec)
11373 type = PointerContainer.MakeType (ec.Module, type);
11374 eclass = ExprClass.Value;
11381 // This class is used to represent the address of an array, used
11382 // only by the Fixed statement, this generates "&a [0]" construct
11383 // for fixed (char *pa = a)
11385 class ArrayPtr : FixedBufferPtr
11387 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11388 base (array, array_type, l)
11392 public override void Emit (EmitContext ec)
11397 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11402 // Encapsulates a conversion rules required for array indexes
11404 public class ArrayIndexCast : TypeCast
11406 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11407 : base (expr, returnType)
11409 if (expr.Type == returnType) // int -> int
11410 throw new ArgumentException ("unnecessary array index conversion");
11413 public override Expression CreateExpressionTree (ResolveContext ec)
11415 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11416 return base.CreateExpressionTree (ec);
11420 public override void Emit (EmitContext ec)
11424 switch (child.Type.BuiltinType) {
11425 case BuiltinTypeSpec.Type.UInt:
11426 ec.Emit (OpCodes.Conv_U);
11428 case BuiltinTypeSpec.Type.Long:
11429 ec.Emit (OpCodes.Conv_Ovf_I);
11431 case BuiltinTypeSpec.Type.ULong:
11432 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11435 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11441 // Implements the `stackalloc' keyword
11443 public class StackAlloc : Expression {
11448 public StackAlloc (Expression type, Expression count, Location l)
11451 this.count = count;
11455 public Expression TypeExpression {
11461 public Expression CountExpression {
11467 public override bool ContainsEmitWithAwait ()
11472 public override Expression CreateExpressionTree (ResolveContext ec)
11474 throw new NotSupportedException ("ET");
11477 protected override Expression DoResolve (ResolveContext ec)
11479 count = count.Resolve (ec);
11483 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11484 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11489 Constant c = count as Constant;
11490 if (c != null && c.IsNegative) {
11491 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11494 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11495 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11498 otype = t.ResolveAsType (ec);
11502 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11505 type = PointerContainer.MakeType (ec.Module, otype);
11506 eclass = ExprClass.Value;
11511 public override void Emit (EmitContext ec)
11513 int size = BuiltinTypeSpec.GetSize (otype);
11518 ec.Emit (OpCodes.Sizeof, otype);
11522 ec.Emit (OpCodes.Mul_Ovf_Un);
11523 ec.Emit (OpCodes.Localloc);
11526 protected override void CloneTo (CloneContext clonectx, Expression t)
11528 StackAlloc target = (StackAlloc) t;
11529 target.count = count.Clone (clonectx);
11530 target.t = t.Clone (clonectx);
11533 public override object Accept (StructuralVisitor visitor)
11535 return visitor.Visit (this);
11540 // An object initializer expression
11542 public class ElementInitializer : Assign
11544 public readonly string Name;
11546 public ElementInitializer (string name, Expression initializer, Location loc)
11547 : base (null, initializer, loc)
11552 public bool IsDictionaryInitializer {
11554 return Name == null;
11558 protected override void CloneTo (CloneContext clonectx, Expression t)
11560 ElementInitializer target = (ElementInitializer) t;
11561 target.source = source.Clone (clonectx);
11564 public override Expression CreateExpressionTree (ResolveContext ec)
11566 Arguments args = new Arguments (2);
11567 FieldExpr fe = target as FieldExpr;
11569 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11571 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11574 Expression arg_expr;
11575 var cinit = source as CollectionOrObjectInitializers;
11576 if (cinit == null) {
11578 arg_expr = source.CreateExpressionTree (ec);
11580 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11581 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11584 args.Add (new Argument (arg_expr));
11585 return CreateExpressionFactoryCall (ec, mname, args);
11588 protected override Expression DoResolve (ResolveContext ec)
11590 if (source == null)
11591 return EmptyExpressionStatement.Instance;
11593 if (!ResolveElement (ec))
11596 if (source is CollectionOrObjectInitializers) {
11597 Expression previous = ec.CurrentInitializerVariable;
11598 ec.CurrentInitializerVariable = target;
11599 source = source.Resolve (ec);
11600 ec.CurrentInitializerVariable = previous;
11601 if (source == null)
11604 eclass = source.eclass;
11605 type = source.Type;
11609 return base.DoResolve (ec);
11612 public override void EmitStatement (EmitContext ec)
11614 if (source is CollectionOrObjectInitializers)
11617 base.EmitStatement (ec);
11620 protected virtual bool ResolveElement (ResolveContext rc)
11622 var t = rc.CurrentInitializerVariable.Type;
11623 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11624 Arguments args = new Arguments (1);
11625 args.Add (new Argument (rc.CurrentInitializerVariable));
11626 target = new DynamicMemberBinder (Name, args, loc);
11629 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11630 if (member == null) {
11631 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11633 if (member != null) {
11634 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11635 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11640 if (member == null) {
11641 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11645 var me = member as MemberExpr;
11646 if (me is EventExpr) {
11647 me = me.ResolveMemberAccess (rc, null, null);
11648 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11649 rc.Report.Error (1913, loc,
11650 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11651 member.GetSignatureForError ());
11657 rc.Report.Error (1914, loc,
11658 "Static field or property `{0}' cannot be assigned in an object initializer",
11659 me.GetSignatureForError ());
11663 me.InstanceExpression = rc.CurrentInitializerVariable;
11671 // A collection initializer expression
11673 class CollectionElementInitializer : Invocation
11675 public class ElementInitializerArgument : Argument
11677 public ElementInitializerArgument (Expression e)
11683 sealed class AddMemberAccess : MemberAccess
11685 public AddMemberAccess (Expression expr, Location loc)
11686 : base (expr, "Add", loc)
11690 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11692 if (TypeManager.HasElementType (type))
11695 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11699 public CollectionElementInitializer (Expression argument)
11700 : base (null, new Arguments (1))
11702 base.arguments.Add (new ElementInitializerArgument (argument));
11703 this.loc = argument.Location;
11706 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11707 : base (null, new Arguments (arguments.Count))
11709 foreach (Expression e in arguments)
11710 base.arguments.Add (new ElementInitializerArgument (e));
11715 public CollectionElementInitializer (Location loc)
11716 : base (null, null)
11721 public override Expression CreateExpressionTree (ResolveContext ec)
11723 Arguments args = new Arguments (2);
11724 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11726 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11727 foreach (Argument a in arguments)
11728 expr_initializers.Add (a.CreateExpressionTree (ec));
11730 args.Add (new Argument (new ArrayCreation (
11731 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11732 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11735 protected override void CloneTo (CloneContext clonectx, Expression t)
11737 CollectionElementInitializer target = (CollectionElementInitializer) t;
11738 if (arguments != null)
11739 target.arguments = arguments.Clone (clonectx);
11742 protected override Expression DoResolve (ResolveContext ec)
11744 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11746 return base.DoResolve (ec);
11750 class DictionaryElementInitializer : ElementInitializer
11752 readonly Arguments args;
11754 public DictionaryElementInitializer (List<Expression> arguments, Expression initializer, Location loc)
11755 : base (null, initializer, loc)
11757 this.args = new Arguments (arguments.Count);
11758 foreach (var arg in arguments)
11759 this.args.Add (new Argument (arg));
11762 public override Expression CreateExpressionTree (ResolveContext ec)
11764 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11768 protected override bool ResolveElement (ResolveContext rc)
11770 var init = rc.CurrentInitializerVariable;
11771 var type = init.Type;
11773 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11774 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11775 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11779 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11785 // A block of object or collection initializers
11787 public class CollectionOrObjectInitializers : ExpressionStatement
11789 IList<Expression> initializers;
11790 bool is_collection_initialization;
11792 public CollectionOrObjectInitializers (Location loc)
11793 : this (new Expression[0], loc)
11797 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11799 this.initializers = initializers;
11803 public IList<Expression> Initializers {
11805 return initializers;
11809 public bool IsEmpty {
11811 return initializers.Count == 0;
11815 public bool IsCollectionInitializer {
11817 return is_collection_initialization;
11821 protected override void CloneTo (CloneContext clonectx, Expression target)
11823 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11825 t.initializers = new List<Expression> (initializers.Count);
11826 foreach (var e in initializers)
11827 t.initializers.Add (e.Clone (clonectx));
11830 public override bool ContainsEmitWithAwait ()
11832 foreach (var e in initializers) {
11833 if (e.ContainsEmitWithAwait ())
11840 public override Expression CreateExpressionTree (ResolveContext ec)
11842 return CreateExpressionTree (ec, false);
11845 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11847 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11848 foreach (Expression e in initializers) {
11849 Expression expr = e.CreateExpressionTree (ec);
11851 expr_initializers.Add (expr);
11855 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11857 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11860 protected override Expression DoResolve (ResolveContext ec)
11862 List<string> element_names = null;
11863 for (int i = 0; i < initializers.Count; ++i) {
11864 Expression initializer = initializers [i];
11865 ElementInitializer element_initializer = initializer as ElementInitializer;
11868 if (element_initializer != null) {
11869 element_names = new List<string> (initializers.Count);
11870 if (!element_initializer.IsDictionaryInitializer)
11871 element_names.Add (element_initializer.Name);
11872 } else if (initializer is CompletingExpression) {
11873 initializer.Resolve (ec);
11874 throw new InternalErrorException ("This line should never be reached");
11876 var t = ec.CurrentInitializerVariable.Type;
11877 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11878 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11879 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11880 "object initializer because type `{1}' does not implement `{2}' interface",
11881 ec.CurrentInitializerVariable.GetSignatureForError (),
11882 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11883 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11886 is_collection_initialization = true;
11889 if (is_collection_initialization != (element_initializer == null)) {
11890 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11891 is_collection_initialization ? "collection initializer" : "object initializer");
11895 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11896 if (element_names.Contains (element_initializer.Name)) {
11897 ec.Report.Error (1912, element_initializer.Location,
11898 "An object initializer includes more than one member `{0}' initialization",
11899 element_initializer.Name);
11901 element_names.Add (element_initializer.Name);
11906 Expression e = initializer.Resolve (ec);
11907 if (e == EmptyExpressionStatement.Instance)
11908 initializers.RemoveAt (i--);
11910 initializers [i] = e;
11913 type = ec.CurrentInitializerVariable.Type;
11914 if (is_collection_initialization) {
11915 if (TypeManager.HasElementType (type)) {
11916 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11917 type.GetSignatureForError ());
11921 eclass = ExprClass.Variable;
11925 public override void Emit (EmitContext ec)
11927 EmitStatement (ec);
11930 public override void EmitStatement (EmitContext ec)
11932 foreach (ExpressionStatement e in initializers) {
11933 // TODO: need location region
11934 ec.Mark (e.Location);
11935 e.EmitStatement (ec);
11939 public override void FlowAnalysis (FlowAnalysisContext fc)
11941 foreach (var initializer in initializers) {
11942 if (initializer != null)
11943 initializer.FlowAnalysis (fc);
11949 // New expression with element/object initializers
11951 public class NewInitialize : New
11954 // This class serves as a proxy for variable initializer target instances.
11955 // A real variable is assigned later when we resolve left side of an
11958 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11960 NewInitialize new_instance;
11962 public InitializerTargetExpression (NewInitialize newInstance)
11964 this.type = newInstance.type;
11965 this.loc = newInstance.loc;
11966 this.eclass = newInstance.eclass;
11967 this.new_instance = newInstance;
11970 public override bool ContainsEmitWithAwait ()
11975 public override Expression CreateExpressionTree (ResolveContext ec)
11977 // Should not be reached
11978 throw new NotSupportedException ("ET");
11981 protected override Expression DoResolve (ResolveContext ec)
11986 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
11991 public override void Emit (EmitContext ec)
11993 Expression e = (Expression) new_instance.instance;
11997 public override Expression EmitToField (EmitContext ec)
11999 return (Expression) new_instance.instance;
12002 #region IMemoryLocation Members
12004 public void AddressOf (EmitContext ec, AddressOp mode)
12006 new_instance.instance.AddressOf (ec, mode);
12012 CollectionOrObjectInitializers initializers;
12013 IMemoryLocation instance;
12014 DynamicExpressionStatement dynamic;
12016 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12017 : base (requested_type, arguments, l)
12019 this.initializers = initializers;
12022 public CollectionOrObjectInitializers Initializers {
12024 return initializers;
12028 protected override void CloneTo (CloneContext clonectx, Expression t)
12030 base.CloneTo (clonectx, t);
12032 NewInitialize target = (NewInitialize) t;
12033 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12036 public override bool ContainsEmitWithAwait ()
12038 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12041 public override Expression CreateExpressionTree (ResolveContext ec)
12043 Arguments args = new Arguments (2);
12044 args.Add (new Argument (base.CreateExpressionTree (ec)));
12045 if (!initializers.IsEmpty)
12046 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12048 return CreateExpressionFactoryCall (ec,
12049 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12053 protected override Expression DoResolve (ResolveContext ec)
12055 Expression e = base.DoResolve (ec);
12059 if (type.IsDelegate) {
12060 ec.Report.Error (1958, Initializers.Location,
12061 "Object and collection initializers cannot be used to instantiate a delegate");
12064 Expression previous = ec.CurrentInitializerVariable;
12065 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12066 initializers.Resolve (ec);
12067 ec.CurrentInitializerVariable = previous;
12069 dynamic = e as DynamicExpressionStatement;
12070 if (dynamic != null)
12076 public override void Emit (EmitContext ec)
12078 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12079 var fe = ec.GetTemporaryField (type);
12081 if (!Emit (ec, fe))
12090 public override bool Emit (EmitContext ec, IMemoryLocation target)
12092 bool left_on_stack;
12093 if (dynamic != null) {
12095 left_on_stack = true;
12097 left_on_stack = base.Emit (ec, target);
12100 if (initializers.IsEmpty)
12101 return left_on_stack;
12103 LocalTemporary temp = null;
12105 instance = target as LocalTemporary;
12106 if (instance == null)
12107 instance = target as StackFieldExpr;
12109 if (instance == null) {
12110 if (!left_on_stack) {
12111 VariableReference vr = target as VariableReference;
12113 // FIXME: This still does not work correctly for pre-set variables
12114 if (vr != null && vr.IsRef)
12115 target.AddressOf (ec, AddressOp.Load);
12117 ((Expression) target).Emit (ec);
12118 left_on_stack = true;
12121 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12122 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
12124 temp = new LocalTemporary (type);
12129 if (left_on_stack && temp != null)
12132 initializers.Emit (ec);
12134 if (left_on_stack) {
12135 if (temp != null) {
12139 ((Expression) instance).Emit (ec);
12143 return left_on_stack;
12146 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12148 instance = base.EmitAddressOf (ec, Mode);
12150 if (!initializers.IsEmpty)
12151 initializers.Emit (ec);
12156 public override void FlowAnalysis (FlowAnalysisContext fc)
12158 base.FlowAnalysis (fc);
12159 initializers.FlowAnalysis (fc);
12162 public override object Accept (StructuralVisitor visitor)
12164 return visitor.Visit (this);
12168 public class NewAnonymousType : New
12170 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12172 List<AnonymousTypeParameter> parameters;
12173 readonly TypeContainer parent;
12174 AnonymousTypeClass anonymous_type;
12176 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12177 : base (null, null, loc)
12179 this.parameters = parameters;
12180 this.parent = parent;
12183 public List<AnonymousTypeParameter> Parameters {
12185 return this.parameters;
12189 protected override void CloneTo (CloneContext clonectx, Expression target)
12191 if (parameters == null)
12194 NewAnonymousType t = (NewAnonymousType) target;
12195 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12196 foreach (AnonymousTypeParameter atp in parameters)
12197 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12200 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12202 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12206 type = AnonymousTypeClass.Create (parent, parameters, loc);
12210 int errors = ec.Report.Errors;
12211 type.CreateContainer ();
12212 type.DefineContainer ();
12214 if ((ec.Report.Errors - errors) == 0) {
12215 parent.Module.AddAnonymousType (type);
12216 type.PrepareEmit ();
12222 public override Expression CreateExpressionTree (ResolveContext ec)
12224 if (parameters == null)
12225 return base.CreateExpressionTree (ec);
12227 var init = new ArrayInitializer (parameters.Count, loc);
12228 foreach (var m in anonymous_type.Members) {
12229 var p = m as Property;
12231 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12234 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12235 foreach (Argument a in arguments)
12236 ctor_args.Add (a.CreateExpressionTree (ec));
12238 Arguments args = new Arguments (3);
12239 args.Add (new Argument (new TypeOfMethod (method, loc)));
12240 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12241 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12243 return CreateExpressionFactoryCall (ec, "New", args);
12246 protected override Expression DoResolve (ResolveContext ec)
12248 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12249 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12253 if (parameters == null) {
12254 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12255 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12256 return base.DoResolve (ec);
12259 bool error = false;
12260 arguments = new Arguments (parameters.Count);
12261 var t_args = new TypeSpec [parameters.Count];
12262 for (int i = 0; i < parameters.Count; ++i) {
12263 Expression e = parameters [i].Resolve (ec);
12269 arguments.Add (new Argument (e));
12270 t_args [i] = e.Type;
12276 anonymous_type = CreateAnonymousType (ec, parameters);
12277 if (anonymous_type == null)
12280 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12281 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12282 eclass = ExprClass.Value;
12286 public override object Accept (StructuralVisitor visitor)
12288 return visitor.Visit (this);
12292 public class AnonymousTypeParameter : ShimExpression
12294 public readonly string Name;
12296 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12297 : base (initializer)
12303 public AnonymousTypeParameter (Parameter parameter)
12304 : base (new SimpleName (parameter.Name, parameter.Location))
12306 this.Name = parameter.Name;
12307 this.loc = parameter.Location;
12310 public override bool Equals (object o)
12312 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12313 return other != null && Name == other.Name;
12316 public override int GetHashCode ()
12318 return Name.GetHashCode ();
12321 protected override Expression DoResolve (ResolveContext ec)
12323 Expression e = expr.Resolve (ec);
12327 if (e.eclass == ExprClass.MethodGroup) {
12328 Error_InvalidInitializer (ec, e.ExprClassName);
12333 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12334 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12341 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12343 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12344 Name, initializer);
12348 public class CatchFilterExpression : BooleanExpression
12350 public CatchFilterExpression (Expression expr, Location loc)