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 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4607 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4609 if (oper == Operator.Subtraction)
4610 expr = ConvertEnumSubtractionResult (rc, expr);
4612 expr = ConvertEnumAdditionalResult (expr, enum_type);
4614 enum_conversion = GetEnumResultCast (expr.Type);
4620 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4622 return EmptyCast.Create (expr, enumType);
4625 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4628 // Enumeration subtraction has different result type based on
4631 TypeSpec result_type;
4632 if (left.Type == right.Type) {
4633 var c = right as EnumConstant;
4634 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4636 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4637 // E which is not what expressions E - 1 or 0 - E return
4639 result_type = left.Type;
4641 result_type = left.Type.IsNullableType ?
4642 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4643 EnumSpec.GetUnderlyingType (left.Type);
4646 if (IsEnumOrNullableEnum (left.Type)) {
4647 result_type = left.Type;
4649 result_type = right.Type;
4652 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4653 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4656 return EmptyCast.Create (expr, result_type);
4659 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4661 if (type.IsNullableType)
4662 type = Nullable.NullableInfo.GetUnderlyingType (type);
4665 type = EnumSpec.GetUnderlyingType (type);
4667 switch (type.BuiltinType) {
4668 case BuiltinTypeSpec.Type.SByte:
4669 return ConvCast.Mode.I4_I1;
4670 case BuiltinTypeSpec.Type.Byte:
4671 return ConvCast.Mode.I4_U1;
4672 case BuiltinTypeSpec.Type.Short:
4673 return ConvCast.Mode.I4_I2;
4674 case BuiltinTypeSpec.Type.UShort:
4675 return ConvCast.Mode.I4_U2;
4682 // Equality operators rules
4684 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4687 type = ec.BuiltinTypes.Bool;
4688 bool no_arg_conv = false;
4690 if (!primitives_only) {
4693 // a, Both operands are reference-type values or the value null
4694 // b, One operand is a value of type T where T is a type-parameter and
4695 // the other operand is the value null. Furthermore T does not have the
4696 // value type constraint
4698 // LAMESPEC: Very confusing details in the specification, basically any
4699 // reference like type-parameter is allowed
4701 var tparam_l = l as TypeParameterSpec;
4702 var tparam_r = r as TypeParameterSpec;
4703 if (tparam_l != null) {
4704 if (right is NullLiteral) {
4705 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4708 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4712 if (!tparam_l.IsReferenceType)
4715 l = tparam_l.GetEffectiveBase ();
4716 left = new BoxedCast (left, l);
4717 } else if (left is NullLiteral && tparam_r == null) {
4718 if (TypeSpec.IsReferenceType (r))
4721 if (r.Kind == MemberKind.InternalCompilerType)
4725 if (tparam_r != null) {
4726 if (left is NullLiteral) {
4727 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4730 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4734 if (!tparam_r.IsReferenceType)
4737 r = tparam_r.GetEffectiveBase ();
4738 right = new BoxedCast (right, r);
4739 } else if (right is NullLiteral) {
4740 if (TypeSpec.IsReferenceType (l))
4743 if (l.Kind == MemberKind.InternalCompilerType)
4748 // LAMESPEC: method groups can be compared when they convert to other side delegate
4751 if (right.eclass == ExprClass.MethodGroup) {
4752 result = Convert.ImplicitConversion (ec, right, l, loc);
4758 } else if (r.IsDelegate && l != r) {
4761 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4762 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4769 no_arg_conv = l == r && !l.IsStruct;
4774 // bool operator != (string a, string b)
4775 // bool operator == (string a, string b)
4777 // bool operator != (Delegate a, Delegate b)
4778 // bool operator == (Delegate a, Delegate b)
4780 // bool operator != (bool a, bool b)
4781 // bool operator == (bool a, bool b)
4783 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4784 // they implement an implicit conversion to any of types above. This does
4785 // not apply when both operands are of same reference type
4787 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4788 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4793 // Now try lifted version of predefined operators
4795 if (no_arg_conv && !l.IsNullableType) {
4797 // Optimizes cases which won't match
4800 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4806 // The == and != operators permit one operand to be a value of a nullable
4807 // type and the other to be the null literal, even if no predefined or user-defined
4808 // operator (in unlifted or lifted form) exists for the operation.
4810 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4811 var lifted = new Nullable.LiftedBinaryOperator (this);
4813 lifted.Right = right;
4814 return lifted.Resolve (ec);
4819 // bool operator != (object a, object b)
4820 // bool operator == (object a, object b)
4822 // An explicit reference conversion exists from the
4823 // type of either operand to the type of the other operand.
4826 // Optimize common path
4828 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4831 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4832 !Convert.ExplicitReferenceConversionExists (r, l))
4835 // Reject allowed explicit conversions like int->object
4836 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4839 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4840 ec.Report.Warning (253, 2, loc,
4841 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4842 l.GetSignatureForError ());
4844 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4845 ec.Report.Warning (252, 2, loc,
4846 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4847 r.GetSignatureForError ());
4853 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4856 // bool operator == (void* x, void* y);
4857 // bool operator != (void* x, void* y);
4858 // bool operator < (void* x, void* y);
4859 // bool operator > (void* x, void* y);
4860 // bool operator <= (void* x, void* y);
4861 // bool operator >= (void* x, void* y);
4863 if ((oper & Operator.ComparisonMask) != 0) {
4866 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4873 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4879 type = ec.BuiltinTypes.Bool;
4883 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4887 // Build-in operators method overloading
4889 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4891 PredefinedOperator best_operator = null;
4892 TypeSpec l = left.Type;
4893 TypeSpec r = right.Type;
4894 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4896 foreach (PredefinedOperator po in operators) {
4897 if ((po.OperatorsMask & oper_mask) == 0)
4900 if (primitives_only) {
4901 if (!po.IsPrimitiveApplicable (l, r))
4904 if (!po.IsApplicable (ec, left, right))
4908 if (best_operator == null) {
4910 if (primitives_only)
4916 best_operator = po.ResolveBetterOperator (ec, best_operator);
4918 if (best_operator == null) {
4919 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4920 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4927 if (best_operator == null)
4930 return best_operator.ConvertResult (ec, this);
4934 // Optimize & constant expressions with 0 value
4936 Expression OptimizeAndOperation (Expression expr)
4938 Constant rc = right as Constant;
4939 Constant lc = left as Constant;
4940 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4942 // The result is a constant with side-effect
4944 Constant side_effect = rc == null ?
4945 new SideEffectConstant (lc, right, loc) :
4946 new SideEffectConstant (rc, left, loc);
4948 return ReducedExpression.Create (side_effect, expr);
4955 // Value types can be compared with the null literal because of the lifting
4956 // language rules. However the result is always true or false.
4958 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4960 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4961 type = rc.BuiltinTypes.Bool;
4965 // FIXME: Handle side effect constants
4966 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4968 if ((Oper & Operator.EqualityMask) != 0) {
4969 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4970 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4972 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4973 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4980 // Performs user-operator overloading
4982 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4984 Expression oper_expr;
4986 var op = ConvertBinaryToUserOperator (oper);
4988 if (l.IsNullableType)
4989 l = Nullable.NullableInfo.GetUnderlyingType (l);
4991 if (r.IsNullableType)
4992 r = Nullable.NullableInfo.GetUnderlyingType (r);
4994 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4995 IList<MemberSpec> right_operators = null;
4998 right_operators = MemberCache.GetUserOperator (r, op, false);
4999 if (right_operators == null && left_operators == null)
5001 } else if (left_operators == null) {
5005 Arguments args = new Arguments (2);
5006 Argument larg = new Argument (left);
5008 Argument rarg = new Argument (right);
5012 // User-defined operator implementations always take precedence
5013 // over predefined operator implementations
5015 if (left_operators != null && right_operators != null) {
5016 left_operators = CombineUserOperators (left_operators, right_operators);
5017 } else if (right_operators != null) {
5018 left_operators = right_operators;
5021 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5022 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5024 var res = new OverloadResolver (left_operators, restr, loc);
5026 var oper_method = res.ResolveOperator (rc, ref args);
5027 if (oper_method == null) {
5029 // Logical && and || cannot be lifted
5031 if ((oper & Operator.LogicalMask) != 0)
5035 // Apply lifted user operators only for liftable types. Implicit conversion
5036 // to nullable types is not allowed
5038 if (!IsLiftedOperatorApplicable ())
5041 // TODO: Cache the result in module container
5042 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5043 if (lifted_methods == null)
5046 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5048 oper_method = res.ResolveOperator (rc, ref args);
5049 if (oper_method == null)
5052 MethodSpec best_original = null;
5053 foreach (MethodSpec ms in left_operators) {
5054 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5060 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5062 // Expression trees use lifted notation in this case
5064 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5065 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5068 var ptypes = best_original.Parameters.Types;
5070 if (left.IsNull || right.IsNull) {
5072 // The lifted operator produces a null value if one or both operands are null
5074 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5075 type = oper_method.ReturnType;
5076 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5080 // The lifted operator produces the value false if one or both operands are null for
5081 // relational operators.
5083 if ((oper & Operator.RelationalMask) != 0) {
5085 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5086 // because return type is actually bool
5088 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5091 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5092 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5096 type = oper_method.ReturnType;
5097 var lifted = new Nullable.LiftedBinaryOperator (this);
5098 lifted.UserOperator = best_original;
5100 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5101 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5104 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5105 lifted.UnwrapRight = new Nullable.Unwrap (right);
5108 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5109 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5111 return lifted.Resolve (rc);
5114 if ((oper & Operator.LogicalMask) != 0) {
5115 // TODO: CreateExpressionTree is allocated every time
5116 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5117 oper == Operator.LogicalAnd, loc).Resolve (rc);
5119 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5122 this.left = larg.Expr;
5123 this.right = rarg.Expr;
5128 bool IsLiftedOperatorApplicable ()
5130 if (left.Type.IsNullableType) {
5131 if ((oper & Operator.EqualityMask) != 0)
5132 return !right.IsNull;
5137 if (right.Type.IsNullableType) {
5138 if ((oper & Operator.EqualityMask) != 0)
5139 return !left.IsNull;
5144 if (TypeSpec.IsValueType (left.Type))
5145 return right.IsNull;
5147 if (TypeSpec.IsValueType (right.Type))
5153 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5155 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5156 if (nullable_type == null)
5160 // Lifted operators permit predefined and user-defined operators that operate
5161 // on non-nullable value types to also be used with nullable forms of those types.
5162 // Lifted operators are constructed from predefined and user-defined operators
5163 // that meet certain requirements
5165 List<MemberSpec> lifted = null;
5166 foreach (MethodSpec oper in operators) {
5168 if ((Oper & Operator.ComparisonMask) != 0) {
5170 // Result type must be of type bool for lifted comparison operators
5172 rt = oper.ReturnType;
5173 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5176 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5182 var ptypes = oper.Parameters.Types;
5183 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5187 // LAMESPEC: I am not sure why but for equality operators to be lifted
5188 // both types have to match
5190 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5194 lifted = new List<MemberSpec> ();
5197 // The lifted form is constructed by adding a single ? modifier to each operand and
5198 // result type except for comparison operators where return type is bool
5201 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5203 var parameters = ParametersCompiled.CreateFullyResolved (
5204 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5205 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5207 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5208 rt, parameters, oper.Modifiers);
5210 lifted.Add (lifted_op);
5217 // Merge two sets of user operators into one, they are mostly distinguish
5218 // except when they share base type and it contains an operator
5220 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5222 var combined = new List<MemberSpec> (left.Count + right.Count);
5223 combined.AddRange (left);
5224 foreach (var r in right) {
5226 foreach (var l in left) {
5227 if (l.DeclaringType == r.DeclaringType) {
5240 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5242 if (c is IntegralConstant || c is CharConstant) {
5244 c.ConvertExplicitly (true, type);
5245 } catch (OverflowException) {
5246 ec.Report.Warning (652, 2, loc,
5247 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5248 type.GetSignatureForError ());
5254 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5255 /// context of a conditional bool expression. This function will return
5256 /// false if it is was possible to use EmitBranchable, or true if it was.
5258 /// The expression's code is generated, and we will generate a branch to `target'
5259 /// if the resulting expression value is equal to isTrue
5261 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5263 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5264 left = left.EmitToField (ec);
5266 if ((oper & Operator.LogicalMask) == 0) {
5267 right = right.EmitToField (ec);
5272 // This is more complicated than it looks, but its just to avoid
5273 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5274 // but on top of that we want for == and != to use a special path
5275 // if we are comparing against null
5277 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5278 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5281 // put the constant on the rhs, for simplicity
5283 if (left is Constant) {
5284 Expression swap = right;
5290 // brtrue/brfalse works with native int only
5292 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5293 left.EmitBranchable (ec, target, my_on_true);
5296 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5297 // right is a boolean, and it's not 'false' => it is 'true'
5298 left.EmitBranchable (ec, target, !my_on_true);
5302 } else if (oper == Operator.LogicalAnd) {
5305 Label tests_end = ec.DefineLabel ();
5307 left.EmitBranchable (ec, tests_end, false);
5308 right.EmitBranchable (ec, target, true);
5309 ec.MarkLabel (tests_end);
5312 // This optimizes code like this
5313 // if (true && i > 4)
5315 if (!(left is Constant))
5316 left.EmitBranchable (ec, target, false);
5318 if (!(right is Constant))
5319 right.EmitBranchable (ec, target, false);
5324 } else if (oper == Operator.LogicalOr){
5326 left.EmitBranchable (ec, target, true);
5327 right.EmitBranchable (ec, target, true);
5330 Label tests_end = ec.DefineLabel ();
5331 left.EmitBranchable (ec, tests_end, true);
5332 right.EmitBranchable (ec, target, false);
5333 ec.MarkLabel (tests_end);
5338 } else if ((oper & Operator.ComparisonMask) == 0) {
5339 base.EmitBranchable (ec, target, on_true);
5346 TypeSpec t = left.Type;
5347 bool is_float = IsFloat (t);
5348 bool is_unsigned = is_float || IsUnsigned (t);
5351 case Operator.Equality:
5353 ec.Emit (OpCodes.Beq, target);
5355 ec.Emit (OpCodes.Bne_Un, target);
5358 case Operator.Inequality:
5360 ec.Emit (OpCodes.Bne_Un, target);
5362 ec.Emit (OpCodes.Beq, target);
5365 case Operator.LessThan:
5367 if (is_unsigned && !is_float)
5368 ec.Emit (OpCodes.Blt_Un, target);
5370 ec.Emit (OpCodes.Blt, target);
5373 ec.Emit (OpCodes.Bge_Un, target);
5375 ec.Emit (OpCodes.Bge, target);
5378 case Operator.GreaterThan:
5380 if (is_unsigned && !is_float)
5381 ec.Emit (OpCodes.Bgt_Un, target);
5383 ec.Emit (OpCodes.Bgt, target);
5386 ec.Emit (OpCodes.Ble_Un, target);
5388 ec.Emit (OpCodes.Ble, target);
5391 case Operator.LessThanOrEqual:
5393 if (is_unsigned && !is_float)
5394 ec.Emit (OpCodes.Ble_Un, target);
5396 ec.Emit (OpCodes.Ble, target);
5399 ec.Emit (OpCodes.Bgt_Un, target);
5401 ec.Emit (OpCodes.Bgt, target);
5405 case Operator.GreaterThanOrEqual:
5407 if (is_unsigned && !is_float)
5408 ec.Emit (OpCodes.Bge_Un, target);
5410 ec.Emit (OpCodes.Bge, target);
5413 ec.Emit (OpCodes.Blt_Un, target);
5415 ec.Emit (OpCodes.Blt, target);
5418 throw new InternalErrorException (oper.ToString ());
5422 public override void Emit (EmitContext ec)
5424 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5425 left = left.EmitToField (ec);
5427 if ((oper & Operator.LogicalMask) == 0) {
5428 right = right.EmitToField (ec);
5433 // Handle short-circuit operators differently
5436 if ((oper & Operator.LogicalMask) != 0) {
5437 Label load_result = ec.DefineLabel ();
5438 Label end = ec.DefineLabel ();
5440 bool is_or = oper == Operator.LogicalOr;
5441 left.EmitBranchable (ec, load_result, is_or);
5443 ec.Emit (OpCodes.Br_S, end);
5445 ec.MarkLabel (load_result);
5446 ec.EmitInt (is_or ? 1 : 0);
5452 // Optimize zero-based operations which cannot be optimized at expression level
5454 if (oper == Operator.Subtraction) {
5455 var lc = left as IntegralConstant;
5456 if (lc != null && lc.IsDefaultValue) {
5458 ec.Emit (OpCodes.Neg);
5463 EmitOperator (ec, left, right);
5466 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5471 EmitOperatorOpcode (ec, oper, left.Type, right);
5474 // Emit result enumerable conversion this way because it's quite complicated get it
5475 // to resolved tree because expression tree cannot see it.
5477 if (enum_conversion != 0)
5478 ConvCast.Emit (ec, enum_conversion);
5481 public override void EmitSideEffect (EmitContext ec)
5483 if ((oper & Operator.LogicalMask) != 0 ||
5484 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5485 base.EmitSideEffect (ec);
5487 left.EmitSideEffect (ec);
5488 right.EmitSideEffect (ec);
5492 public override Expression EmitToField (EmitContext ec)
5494 if ((oper & Operator.LogicalMask) == 0) {
5495 var await_expr = left as Await;
5496 if (await_expr != null && right.IsSideEffectFree) {
5497 await_expr.Statement.EmitPrologue (ec);
5498 left = await_expr.Statement.GetResultExpression (ec);
5502 await_expr = right as Await;
5503 if (await_expr != null && left.IsSideEffectFree) {
5504 await_expr.Statement.EmitPrologue (ec);
5505 right = await_expr.Statement.GetResultExpression (ec);
5510 return base.EmitToField (ec);
5513 protected override void CloneTo (CloneContext clonectx, Expression t)
5515 Binary target = (Binary) t;
5517 target.left = left.Clone (clonectx);
5518 target.right = right.Clone (clonectx);
5521 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5523 Arguments binder_args = new Arguments (4);
5525 MemberAccess sle = new MemberAccess (new MemberAccess (
5526 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5528 CSharpBinderFlags flags = 0;
5529 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5530 flags = CSharpBinderFlags.CheckedContext;
5532 if ((oper & Operator.LogicalMask) != 0)
5533 flags |= CSharpBinderFlags.BinaryOperationLogical;
5535 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5536 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5537 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5538 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5540 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5543 public override Expression CreateExpressionTree (ResolveContext ec)
5545 return CreateExpressionTree (ec, null);
5548 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5551 bool lift_arg = false;
5554 case Operator.Addition:
5555 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5556 method_name = "AddChecked";
5558 method_name = "Add";
5560 case Operator.BitwiseAnd:
5561 method_name = "And";
5563 case Operator.BitwiseOr:
5566 case Operator.Division:
5567 method_name = "Divide";
5569 case Operator.Equality:
5570 method_name = "Equal";
5573 case Operator.ExclusiveOr:
5574 method_name = "ExclusiveOr";
5576 case Operator.GreaterThan:
5577 method_name = "GreaterThan";
5580 case Operator.GreaterThanOrEqual:
5581 method_name = "GreaterThanOrEqual";
5584 case Operator.Inequality:
5585 method_name = "NotEqual";
5588 case Operator.LeftShift:
5589 method_name = "LeftShift";
5591 case Operator.LessThan:
5592 method_name = "LessThan";
5595 case Operator.LessThanOrEqual:
5596 method_name = "LessThanOrEqual";
5599 case Operator.LogicalAnd:
5600 method_name = "AndAlso";
5602 case Operator.LogicalOr:
5603 method_name = "OrElse";
5605 case Operator.Modulus:
5606 method_name = "Modulo";
5608 case Operator.Multiply:
5609 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5610 method_name = "MultiplyChecked";
5612 method_name = "Multiply";
5614 case Operator.RightShift:
5615 method_name = "RightShift";
5617 case Operator.Subtraction:
5618 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5619 method_name = "SubtractChecked";
5621 method_name = "Subtract";
5625 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5628 Arguments args = new Arguments (2);
5629 args.Add (new Argument (left.CreateExpressionTree (ec)));
5630 args.Add (new Argument (right.CreateExpressionTree (ec)));
5631 if (method != null) {
5633 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5635 args.Add (new Argument (method));
5638 return CreateExpressionFactoryCall (ec, method_name, args);
5641 public override object Accept (StructuralVisitor visitor)
5643 return visitor.Visit (this);
5649 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5650 // b, c, d... may be strings or objects.
5652 public class StringConcat : Expression
5654 Arguments arguments;
5656 StringConcat (Location loc)
5659 arguments = new Arguments (2);
5662 public override bool ContainsEmitWithAwait ()
5664 return arguments.ContainsEmitWithAwait ();
5667 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5669 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5670 throw new ArgumentException ();
5672 var s = new StringConcat (loc);
5673 s.type = rc.BuiltinTypes.String;
5674 s.eclass = ExprClass.Value;
5676 s.Append (rc, left);
5677 s.Append (rc, right);
5681 public override Expression CreateExpressionTree (ResolveContext ec)
5683 Argument arg = arguments [0];
5684 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5688 // Creates nested calls tree from an array of arguments used for IL emit
5690 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5692 Arguments concat_args = new Arguments (2);
5693 Arguments add_args = new Arguments (3);
5695 concat_args.Add (left);
5696 add_args.Add (new Argument (left_etree));
5698 concat_args.Add (arguments [pos]);
5699 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5701 var methods = GetConcatMethodCandidates ();
5702 if (methods == null)
5705 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5706 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5710 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5712 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5713 if (++pos == arguments.Count)
5716 left = new Argument (new EmptyExpression (method.ReturnType));
5717 return CreateExpressionAddCall (ec, left, expr, pos);
5720 protected override Expression DoResolve (ResolveContext ec)
5725 void Append (ResolveContext rc, Expression operand)
5730 StringConstant sc = operand as StringConstant;
5732 if (arguments.Count != 0) {
5733 Argument last_argument = arguments [arguments.Count - 1];
5734 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5735 if (last_expr_constant != null) {
5736 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5742 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5744 StringConcat concat_oper = operand as StringConcat;
5745 if (concat_oper != null) {
5746 arguments.AddRange (concat_oper.arguments);
5751 arguments.Add (new Argument (operand));
5754 IList<MemberSpec> GetConcatMethodCandidates ()
5756 return MemberCache.FindMembers (type, "Concat", true);
5759 public override void Emit (EmitContext ec)
5761 // Optimize by removing any extra null arguments, they are no-op
5762 for (int i = 0; i < arguments.Count; ++i) {
5763 if (arguments[i].Expr is NullConstant)
5764 arguments.RemoveAt (i--);
5767 var members = GetConcatMethodCandidates ();
5768 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5769 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5770 if (method != null) {
5771 var call = new CallEmitter ();
5772 call.EmitPredefined (ec, method, arguments, false);
5776 public override void FlowAnalysis (FlowAnalysisContext fc)
5778 arguments.FlowAnalysis (fc);
5781 public override SLE.Expression MakeExpression (BuilderContext ctx)
5783 if (arguments.Count != 2)
5784 throw new NotImplementedException ("arguments.Count != 2");
5786 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5787 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5792 // User-defined conditional logical operator
5794 public class ConditionalLogicalOperator : UserOperatorCall
5796 readonly bool is_and;
5797 Expression oper_expr;
5799 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5800 : base (oper, arguments, expr_tree, loc)
5802 this.is_and = is_and;
5803 eclass = ExprClass.Unresolved;
5806 protected override Expression DoResolve (ResolveContext ec)
5808 AParametersCollection pd = oper.Parameters;
5809 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5810 ec.Report.Error (217, loc,
5811 "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",
5812 oper.GetSignatureForError ());
5816 Expression left_dup = new EmptyExpression (type);
5817 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5818 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5819 if (op_true == null || op_false == null) {
5820 ec.Report.Error (218, loc,
5821 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5822 type.GetSignatureForError (), oper.GetSignatureForError ());
5826 oper_expr = is_and ? op_false : op_true;
5827 eclass = ExprClass.Value;
5831 public override void Emit (EmitContext ec)
5833 Label end_target = ec.DefineLabel ();
5836 // Emit and duplicate left argument
5838 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5839 if (right_contains_await) {
5840 arguments[0] = arguments[0].EmitToField (ec, false);
5841 arguments[0].Expr.Emit (ec);
5843 arguments[0].Expr.Emit (ec);
5844 ec.Emit (OpCodes.Dup);
5845 arguments.RemoveAt (0);
5848 oper_expr.EmitBranchable (ec, end_target, true);
5852 if (right_contains_await) {
5854 // Special handling when right expression contains await and left argument
5855 // could not be left on stack before logical branch
5857 Label skip_left_load = ec.DefineLabel ();
5858 ec.Emit (OpCodes.Br_S, skip_left_load);
5859 ec.MarkLabel (end_target);
5860 arguments[0].Expr.Emit (ec);
5861 ec.MarkLabel (skip_left_load);
5863 ec.MarkLabel (end_target);
5868 public class PointerArithmetic : Expression {
5869 Expression left, right;
5870 readonly Binary.Operator op;
5873 // We assume that `l' is always a pointer
5875 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5884 public override bool ContainsEmitWithAwait ()
5886 throw new NotImplementedException ();
5889 public override Expression CreateExpressionTree (ResolveContext ec)
5891 Error_PointerInsideExpressionTree (ec);
5895 protected override Expression DoResolve (ResolveContext ec)
5897 eclass = ExprClass.Variable;
5899 var pc = left.Type as PointerContainer;
5900 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5901 Error_VoidPointerOperation (ec);
5908 public override void Emit (EmitContext ec)
5910 TypeSpec op_type = left.Type;
5912 // It must be either array or fixed buffer
5914 if (TypeManager.HasElementType (op_type)) {
5915 element = TypeManager.GetElementType (op_type);
5917 FieldExpr fe = left as FieldExpr;
5919 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5924 int size = BuiltinTypeSpec.GetSize(element);
5925 TypeSpec rtype = right.Type;
5927 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5929 // handle (pointer - pointer)
5933 ec.Emit (OpCodes.Sub);
5937 ec.Emit (OpCodes.Sizeof, element);
5940 ec.Emit (OpCodes.Div);
5942 ec.Emit (OpCodes.Conv_I8);
5945 // handle + and - on (pointer op int)
5947 Constant left_const = left as Constant;
5948 if (left_const != null) {
5950 // Optimize ((T*)null) pointer operations
5952 if (left_const.IsDefaultValue) {
5953 left = EmptyExpression.Null;
5961 var right_const = right as Constant;
5962 if (right_const != null) {
5964 // Optimize 0-based arithmetic
5966 if (right_const.IsDefaultValue)
5970 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5972 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5974 // TODO: Should be the checks resolve context sensitive?
5975 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5976 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5982 switch (rtype.BuiltinType) {
5983 case BuiltinTypeSpec.Type.SByte:
5984 case BuiltinTypeSpec.Type.Byte:
5985 case BuiltinTypeSpec.Type.Short:
5986 case BuiltinTypeSpec.Type.UShort:
5987 ec.Emit (OpCodes.Conv_I);
5989 case BuiltinTypeSpec.Type.UInt:
5990 ec.Emit (OpCodes.Conv_U);
5994 if (right_const == null && size != 1){
5996 ec.Emit (OpCodes.Sizeof, element);
5999 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6000 ec.Emit (OpCodes.Conv_I8);
6002 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6005 if (left_const == null) {
6006 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6007 ec.Emit (OpCodes.Conv_I);
6008 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6009 ec.Emit (OpCodes.Conv_U);
6011 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6018 // A boolean-expression is an expression that yields a result
6021 public class BooleanExpression : ShimExpression
6023 public BooleanExpression (Expression expr)
6026 this.loc = expr.Location;
6029 public override Expression CreateExpressionTree (ResolveContext ec)
6031 // TODO: We should emit IsTrue (v4) instead of direct user operator
6032 // call but that would break csc compatibility
6033 return base.CreateExpressionTree (ec);
6036 protected override Expression DoResolve (ResolveContext ec)
6038 // A boolean-expression is required to be of a type
6039 // that can be implicitly converted to bool or of
6040 // a type that implements operator true
6042 expr = expr.Resolve (ec);
6046 Assign ass = expr as Assign;
6047 if (ass != null && ass.Source is Constant) {
6048 ec.Report.Warning (665, 3, loc,
6049 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6052 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6055 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6056 Arguments args = new Arguments (1);
6057 args.Add (new Argument (expr));
6058 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6061 type = ec.BuiltinTypes.Bool;
6062 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6063 if (converted != null)
6067 // If no implicit conversion to bool exists, try using `operator true'
6069 converted = GetOperatorTrue (ec, expr, loc);
6070 if (converted == null) {
6071 expr.Error_ValueCannotBeConverted (ec, type, false);
6078 public override object Accept (StructuralVisitor visitor)
6080 return visitor.Visit (this);
6084 public class BooleanExpressionFalse : Unary
6086 public BooleanExpressionFalse (Expression expr)
6087 : base (Operator.LogicalNot, expr, expr.Location)
6091 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6093 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6098 /// Implements the ternary conditional operator (?:)
6100 public class Conditional : Expression {
6101 Expression expr, true_expr, false_expr;
6103 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6106 this.true_expr = true_expr;
6107 this.false_expr = false_expr;
6113 public Expression Expr {
6119 public Expression TrueExpr {
6125 public Expression FalseExpr {
6133 public override bool ContainsEmitWithAwait ()
6135 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6138 public override Expression CreateExpressionTree (ResolveContext ec)
6140 Arguments args = new Arguments (3);
6141 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6142 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6143 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6144 return CreateExpressionFactoryCall (ec, "Condition", args);
6147 protected override Expression DoResolve (ResolveContext ec)
6149 expr = expr.Resolve (ec);
6150 true_expr = true_expr.Resolve (ec);
6151 false_expr = false_expr.Resolve (ec);
6153 if (true_expr == null || false_expr == null || expr == null)
6156 eclass = ExprClass.Value;
6157 TypeSpec true_type = true_expr.Type;
6158 TypeSpec false_type = false_expr.Type;
6162 // First, if an implicit conversion exists from true_expr
6163 // to false_expr, then the result type is of type false_expr.Type
6165 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6166 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6167 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6169 // Check if both can convert implicitly to each other's type
6173 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6174 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6176 // LAMESPEC: There seems to be hardcoded promotition to int type when
6177 // both sides are numeric constants and one side is int constant and
6178 // other side is numeric constant convertible to int.
6180 // var res = condition ? (short)1 : 1;
6182 // Type of res is int even if according to the spec the conversion is
6183 // ambiguous because 1 literal can be converted to short.
6185 if (conv_false_expr != null) {
6186 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6188 conv_false_expr = null;
6189 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6190 conv_false_expr = null;
6194 if (conv_false_expr != null) {
6195 ec.Report.Error (172, true_expr.Location,
6196 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6197 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6202 if (true_expr.Type != type)
6203 true_expr = EmptyCast.Create (true_expr, type);
6204 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6207 ec.Report.Error (173, true_expr.Location,
6208 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6209 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6214 Constant c = expr as Constant;
6216 bool is_false = c.IsDefaultValue;
6219 // Don't issue the warning for constant expressions
6221 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6222 // CSC: Missing warning
6223 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6226 return ReducedExpression.Create (
6227 is_false ? false_expr : true_expr, this,
6228 false_expr is Constant && true_expr is Constant).Resolve (ec);
6234 public override void Emit (EmitContext ec)
6236 Label false_target = ec.DefineLabel ();
6237 Label end_target = ec.DefineLabel ();
6239 expr.EmitBranchable (ec, false_target, false);
6240 true_expr.Emit (ec);
6243 // Verifier doesn't support interface merging. When there are two types on
6244 // the stack without common type hint and the common type is an interface.
6245 // Use temporary local to give verifier hint on what type to unify the stack
6247 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6248 var temp = ec.GetTemporaryLocal (type);
6249 ec.Emit (OpCodes.Stloc, temp);
6250 ec.Emit (OpCodes.Ldloc, temp);
6251 ec.FreeTemporaryLocal (temp, type);
6254 ec.Emit (OpCodes.Br, end_target);
6255 ec.MarkLabel (false_target);
6256 false_expr.Emit (ec);
6257 ec.MarkLabel (end_target);
6260 public override void FlowAnalysis (FlowAnalysisContext fc)
6262 expr.FlowAnalysisConditional (fc);
6263 var expr_true = fc.DefiniteAssignmentOnTrue;
6264 var expr_false = fc.DefiniteAssignmentOnFalse;
6266 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6267 true_expr.FlowAnalysis (fc);
6268 var true_fc = fc.DefiniteAssignment;
6270 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6271 false_expr.FlowAnalysis (fc);
6273 fc.DefiniteAssignment &= true_fc;
6276 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6278 expr.FlowAnalysisConditional (fc);
6279 var expr_true = fc.DefiniteAssignmentOnTrue;
6280 var expr_false = fc.DefiniteAssignmentOnFalse;
6282 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6283 true_expr.FlowAnalysisConditional (fc);
6284 var true_fc = fc.DefiniteAssignment;
6285 var true_da_true = fc.DefiniteAssignmentOnTrue;
6286 var true_da_false = fc.DefiniteAssignmentOnFalse;
6288 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6289 false_expr.FlowAnalysisConditional (fc);
6291 fc.DefiniteAssignment &= true_fc;
6292 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6293 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6296 protected override void CloneTo (CloneContext clonectx, Expression t)
6298 Conditional target = (Conditional) t;
6300 target.expr = expr.Clone (clonectx);
6301 target.true_expr = true_expr.Clone (clonectx);
6302 target.false_expr = false_expr.Clone (clonectx);
6306 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6308 LocalTemporary temp;
6311 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6312 public abstract void SetHasAddressTaken ();
6314 public abstract bool IsLockedByStatement { get; set; }
6316 public abstract bool IsFixed { get; }
6317 public abstract bool IsRef { get; }
6318 public abstract string Name { get; }
6321 // Variable IL data, it has to be protected to encapsulate hoisted variables
6323 protected abstract ILocalVariable Variable { get; }
6326 // Variable flow-analysis data
6328 public abstract VariableInfo VariableInfo { get; }
6331 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6333 HoistedVariable hv = GetHoistedVariable (ec);
6335 hv.AddressOf (ec, mode);
6339 Variable.EmitAddressOf (ec);
6342 public override bool ContainsEmitWithAwait ()
6347 public override Expression CreateExpressionTree (ResolveContext ec)
6349 HoistedVariable hv = GetHoistedVariable (ec);
6351 return hv.CreateExpressionTree ();
6353 Arguments arg = new Arguments (1);
6354 arg.Add (new Argument (this));
6355 return CreateExpressionFactoryCall (ec, "Constant", arg);
6358 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6360 if (IsLockedByStatement) {
6361 rc.Report.Warning (728, 2, loc,
6362 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6369 public override void Emit (EmitContext ec)
6374 public override void EmitSideEffect (EmitContext ec)
6380 // This method is used by parameters that are references, that are
6381 // being passed as references: we only want to pass the pointer (that
6382 // is already stored in the parameter, not the address of the pointer,
6383 // and not the value of the variable).
6385 public void EmitLoad (EmitContext ec)
6390 public void Emit (EmitContext ec, bool leave_copy)
6392 HoistedVariable hv = GetHoistedVariable (ec);
6394 hv.Emit (ec, leave_copy);
6402 // If we are a reference, we loaded on the stack a pointer
6403 // Now lets load the real value
6405 ec.EmitLoadFromPtr (type);
6409 ec.Emit (OpCodes.Dup);
6412 temp = new LocalTemporary (Type);
6418 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6419 bool prepare_for_load)
6421 HoistedVariable hv = GetHoistedVariable (ec);
6423 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6427 New n_source = source as New;
6428 if (n_source != null) {
6429 if (!n_source.Emit (ec, this)) {
6433 ec.EmitLoadFromPtr (type);
6445 ec.Emit (OpCodes.Dup);
6447 temp = new LocalTemporary (Type);
6453 ec.EmitStoreFromPtr (type);
6455 Variable.EmitAssign (ec);
6463 public override Expression EmitToField (EmitContext ec)
6465 HoistedVariable hv = GetHoistedVariable (ec);
6467 return hv.EmitToField (ec);
6470 return base.EmitToField (ec);
6473 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6475 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6478 public HoistedVariable GetHoistedVariable (EmitContext ec)
6480 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6483 public override string GetSignatureForError ()
6488 public bool IsHoisted {
6489 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6494 // Resolved reference to a local variable
6496 public class LocalVariableReference : VariableReference
6498 public LocalVariable local_info;
6500 public LocalVariableReference (LocalVariable li, Location l)
6502 this.local_info = li;
6506 public override VariableInfo VariableInfo {
6507 get { return local_info.VariableInfo; }
6510 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6512 return local_info.HoistedVariant;
6518 // A local variable is always fixed
6520 public override bool IsFixed {
6526 public override bool IsLockedByStatement {
6528 return local_info.IsLocked;
6531 local_info.IsLocked = value;
6535 public override bool IsRef {
6536 get { return false; }
6539 public override string Name {
6540 get { return local_info.Name; }
6545 public override void FlowAnalysis (FlowAnalysisContext fc)
6547 VariableInfo variable_info = VariableInfo;
6548 if (variable_info == null)
6551 if (fc.IsDefinitelyAssigned (variable_info))
6554 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6555 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6558 public override void SetHasAddressTaken ()
6560 local_info.SetHasAddressTaken ();
6563 void DoResolveBase (ResolveContext ec)
6565 eclass = ExprClass.Variable;
6566 type = local_info.Type;
6569 // If we are referencing a variable from the external block
6570 // flag it for capturing
6572 if (ec.MustCaptureVariable (local_info)) {
6573 if (local_info.AddressTaken) {
6574 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6575 } else if (local_info.IsFixed) {
6576 ec.Report.Error (1764, loc,
6577 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6578 GetSignatureForError ());
6581 if (ec.IsVariableCapturingRequired) {
6582 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6583 storey.CaptureLocalVariable (ec, local_info);
6588 protected override Expression DoResolve (ResolveContext ec)
6590 local_info.SetIsUsed ();
6594 if (local_info.Type == InternalType.VarOutType) {
6595 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6596 GetSignatureForError ());
6598 type = InternalType.ErrorType;
6604 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6607 // Don't be too pedantic when variable is used as out param or for some broken code
6608 // which uses property/indexer access to run some initialization
6610 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6611 local_info.SetIsUsed ();
6613 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6614 if (rhs == EmptyExpression.LValueMemberAccess) {
6615 // CS1654 already reported
6619 if (rhs == EmptyExpression.OutAccess) {
6620 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6621 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6622 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6623 } else if (rhs == EmptyExpression.UnaryAddress) {
6624 code = 459; msg = "Cannot take the address of {1} `{0}'";
6626 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6628 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6632 if (eclass == ExprClass.Unresolved)
6635 return base.DoResolveLValue (ec, rhs);
6638 public override int GetHashCode ()
6640 return local_info.GetHashCode ();
6643 public override bool Equals (object obj)
6645 LocalVariableReference lvr = obj as LocalVariableReference;
6649 return local_info == lvr.local_info;
6652 protected override ILocalVariable Variable {
6653 get { return local_info; }
6656 public override string ToString ()
6658 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6661 protected override void CloneTo (CloneContext clonectx, Expression t)
6668 /// This represents a reference to a parameter in the intermediate
6671 public class ParameterReference : VariableReference
6673 protected ParametersBlock.ParameterInfo pi;
6675 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6683 public override bool IsLockedByStatement {
6688 pi.IsLocked = value;
6692 public override bool IsRef {
6693 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6696 bool HasOutModifier {
6697 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6700 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6702 return pi.Parameter.HoistedVariant;
6706 // A ref or out parameter is classified as a moveable variable, even
6707 // if the argument given for the parameter is a fixed variable
6709 public override bool IsFixed {
6710 get { return !IsRef; }
6713 public override string Name {
6714 get { return Parameter.Name; }
6717 public Parameter Parameter {
6718 get { return pi.Parameter; }
6721 public override VariableInfo VariableInfo {
6722 get { return pi.VariableInfo; }
6725 protected override ILocalVariable Variable {
6726 get { return Parameter; }
6731 public override void AddressOf (EmitContext ec, AddressOp mode)
6734 // ParameterReferences might already be a reference
6741 base.AddressOf (ec, mode);
6744 public override void SetHasAddressTaken ()
6746 Parameter.HasAddressTaken = true;
6749 bool DoResolveBase (ResolveContext ec)
6751 if (eclass != ExprClass.Unresolved)
6754 type = pi.ParameterType;
6755 eclass = ExprClass.Variable;
6758 // If we are referencing a parameter from the external block
6759 // flag it for capturing
6761 if (ec.MustCaptureVariable (pi)) {
6762 if (Parameter.HasAddressTaken)
6763 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6766 ec.Report.Error (1628, loc,
6767 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6768 Name, ec.CurrentAnonymousMethod.ContainerType);
6771 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6772 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6773 storey.CaptureParameter (ec, pi, this);
6780 public override int GetHashCode ()
6782 return Name.GetHashCode ();
6785 public override bool Equals (object obj)
6787 ParameterReference pr = obj as ParameterReference;
6791 return Name == pr.Name;
6794 protected override void CloneTo (CloneContext clonectx, Expression target)
6800 public override Expression CreateExpressionTree (ResolveContext ec)
6802 HoistedVariable hv = GetHoistedVariable (ec);
6804 return hv.CreateExpressionTree ();
6806 return Parameter.ExpressionTreeVariableReference ();
6809 protected override Expression DoResolve (ResolveContext ec)
6811 if (!DoResolveBase (ec))
6817 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6819 if (!DoResolveBase (ec))
6822 if (Parameter.HoistedVariant != null)
6823 Parameter.HoistedVariant.IsAssigned = true;
6825 return base.DoResolveLValue (ec, right_side);
6828 public override void FlowAnalysis (FlowAnalysisContext fc)
6830 VariableInfo variable_info = VariableInfo;
6831 if (variable_info == null)
6834 if (fc.IsDefinitelyAssigned (variable_info))
6837 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6838 fc.SetVariableAssigned (variable_info);
6843 /// Invocation of methods or delegates.
6845 public class Invocation : ExpressionStatement
6847 public class Predefined : Invocation
6849 public Predefined (MethodGroupExpr expr, Arguments arguments)
6850 : base (expr, arguments)
6855 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6857 if (!rc.IsObsolete) {
6858 var member = mg.BestCandidate;
6859 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6861 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6868 protected Arguments arguments;
6869 protected Expression expr;
6870 protected MethodGroupExpr mg;
6871 bool conditional_access_receiver;
6873 public Invocation (Expression expr, Arguments arguments)
6876 this.arguments = arguments;
6878 loc = expr.Location;
6883 public Arguments Arguments {
6889 public Expression Exp {
6895 public MethodGroupExpr MethodGroup {
6901 public override Location StartLocation {
6903 return expr.StartLocation;
6909 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6911 if (MethodGroup == null)
6914 var candidate = MethodGroup.BestCandidate;
6915 if (candidate == null || !(candidate.IsStatic || Exp is This))
6918 var args_count = arguments == null ? 0 : arguments.Count;
6919 if (args_count != body.Parameters.Count)
6922 var lambda_parameters = body.Block.Parameters.FixedParameters;
6923 for (int i = 0; i < args_count; ++i) {
6924 var pr = arguments[i].Expr as ParameterReference;
6928 if (lambda_parameters[i] != pr.Parameter)
6931 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6935 var emg = MethodGroup as ExtensionMethodGroupExpr;
6937 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6938 if (candidate.IsGeneric) {
6939 var targs = new TypeExpression [candidate.Arity];
6940 for (int i = 0; i < targs.Length; ++i) {
6941 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6944 mg.SetTypeArguments (null, new TypeArguments (targs));
6953 protected override void CloneTo (CloneContext clonectx, Expression t)
6955 Invocation target = (Invocation) t;
6957 if (arguments != null)
6958 target.arguments = arguments.Clone (clonectx);
6960 target.expr = expr.Clone (clonectx);
6963 public override bool ContainsEmitWithAwait ()
6965 if (arguments != null && arguments.ContainsEmitWithAwait ())
6968 return mg.ContainsEmitWithAwait ();
6971 public override Expression CreateExpressionTree (ResolveContext ec)
6973 Expression instance = mg.IsInstance ?
6974 mg.InstanceExpression.CreateExpressionTree (ec) :
6975 new NullLiteral (loc);
6977 var args = Arguments.CreateForExpressionTree (ec, arguments,
6979 mg.CreateExpressionTree (ec));
6981 return CreateExpressionFactoryCall (ec, "Call", args);
6984 protected override Expression DoResolve (ResolveContext rc)
6986 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
6987 if (expr.HasConditionalAccess ()) {
6988 conditional_access_receiver = true;
6989 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
6990 return DoResolveInvocation (rc);
6995 return DoResolveInvocation (rc);
6998 Expression DoResolveInvocation (ResolveContext ec)
7000 Expression member_expr;
7001 var atn = expr as ATypeNameExpression;
7003 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7004 if (member_expr != null) {
7005 var name_of = member_expr as NameOf;
7006 if (name_of != null) {
7007 return name_of.ResolveOverload (ec, arguments);
7010 member_expr = member_expr.Resolve (ec);
7013 member_expr = expr.Resolve (ec);
7016 if (member_expr == null)
7020 // Next, evaluate all the expressions in the argument list
7022 bool dynamic_arg = false;
7023 if (arguments != null)
7024 arguments.Resolve (ec, out dynamic_arg);
7026 TypeSpec expr_type = member_expr.Type;
7027 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7028 return DoResolveDynamic (ec, member_expr);
7030 mg = member_expr as MethodGroupExpr;
7031 Expression invoke = null;
7034 if (expr_type != null && expr_type.IsDelegate) {
7035 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7036 invoke = invoke.Resolve (ec);
7037 if (invoke == null || !dynamic_arg)
7040 if (member_expr is RuntimeValueExpression) {
7041 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7042 member_expr.Type.GetSignatureForError ());
7046 MemberExpr me = member_expr as MemberExpr;
7048 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7052 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7053 member_expr.GetSignatureForError ());
7058 if (invoke == null) {
7059 mg = DoResolveOverload (ec);
7065 return DoResolveDynamic (ec, member_expr);
7067 var method = mg.BestCandidate;
7068 type = mg.BestCandidateReturnType;
7069 if (conditional_access_receiver)
7070 type = LiftMemberType (ec, type);
7072 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7074 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7076 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7080 IsSpecialMethodInvocation (ec, method, loc);
7082 eclass = ExprClass.Value;
7086 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7089 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7091 args = dmb.Arguments;
7092 if (arguments != null)
7093 args.AddRange (arguments);
7094 } else if (mg == null) {
7095 if (arguments == null)
7096 args = new Arguments (1);
7100 args.Insert (0, new Argument (memberExpr));
7104 ec.Report.Error (1971, loc,
7105 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7110 if (arguments == null)
7111 args = new Arguments (1);
7115 MemberAccess ma = expr as MemberAccess;
7117 var inst = mg.InstanceExpression;
7118 var left_type = inst as TypeExpr;
7119 if (left_type != null) {
7120 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7121 } else if (inst != null) {
7123 // Any value type has to be pass as by-ref to get back the same
7124 // instance on which the member was called
7126 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7127 Argument.AType.Ref : Argument.AType.None;
7128 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7130 } else { // is SimpleName
7132 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7134 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7139 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7142 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7144 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7147 public override void FlowAnalysis (FlowAnalysisContext fc)
7149 if (mg.IsConditionallyExcluded)
7152 mg.FlowAnalysis (fc);
7154 if (arguments != null)
7155 arguments.FlowAnalysis (fc);
7157 if (conditional_access_receiver)
7158 fc.ConditionalAccessEnd ();
7161 public override string GetSignatureForError ()
7163 return mg.GetSignatureForError ();
7166 public override bool HasConditionalAccess ()
7168 return expr.HasConditionalAccess ();
7172 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7173 // or the type dynamic, then the member is invocable
7175 public static bool IsMemberInvocable (MemberSpec member)
7177 switch (member.Kind) {
7178 case MemberKind.Event:
7180 case MemberKind.Field:
7181 case MemberKind.Property:
7182 var m = member as IInterfaceMemberSpec;
7183 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7189 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7191 if (!method.IsReservedMethod)
7194 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7197 ec.Report.SymbolRelatedToPreviousError (method);
7198 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7199 method.GetSignatureForError ());
7204 public override void Emit (EmitContext ec)
7206 if (mg.IsConditionallyExcluded)
7209 if (conditional_access_receiver)
7210 mg.EmitCall (ec, arguments, type, false);
7212 mg.EmitCall (ec, arguments, false);
7215 public override void EmitStatement (EmitContext ec)
7217 if (mg.IsConditionallyExcluded)
7220 if (conditional_access_receiver)
7221 mg.EmitCall (ec, arguments, type, true);
7223 mg.EmitCall (ec, arguments, true);
7226 public override SLE.Expression MakeExpression (BuilderContext ctx)
7228 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7231 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7234 throw new NotSupportedException ();
7236 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7237 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7241 public override object Accept (StructuralVisitor visitor)
7243 return visitor.Visit (this);
7248 // Implements simple new expression
7250 public class New : ExpressionStatement, IMemoryLocation
7252 protected Arguments arguments;
7255 // During bootstrap, it contains the RequestedType,
7256 // but if `type' is not null, it *might* contain a NewDelegate
7257 // (because of field multi-initialization)
7259 protected Expression RequestedType;
7261 protected MethodSpec method;
7263 public New (Expression requested_type, Arguments arguments, Location l)
7265 RequestedType = requested_type;
7266 this.arguments = arguments;
7271 public Arguments Arguments {
7278 // Returns true for resolved `new S()'
7280 public bool IsDefaultStruct {
7282 return arguments == null && type.IsStruct && GetType () == typeof (New);
7286 public Expression TypeExpression {
7288 return RequestedType;
7295 /// Converts complex core type syntax like 'new int ()' to simple constant
7297 public static Constant Constantify (TypeSpec t, Location loc)
7299 switch (t.BuiltinType) {
7300 case BuiltinTypeSpec.Type.Int:
7301 return new IntConstant (t, 0, loc);
7302 case BuiltinTypeSpec.Type.UInt:
7303 return new UIntConstant (t, 0, loc);
7304 case BuiltinTypeSpec.Type.Long:
7305 return new LongConstant (t, 0, loc);
7306 case BuiltinTypeSpec.Type.ULong:
7307 return new ULongConstant (t, 0, loc);
7308 case BuiltinTypeSpec.Type.Float:
7309 return new FloatConstant (t, 0, loc);
7310 case BuiltinTypeSpec.Type.Double:
7311 return new DoubleConstant (t, 0, loc);
7312 case BuiltinTypeSpec.Type.Short:
7313 return new ShortConstant (t, 0, loc);
7314 case BuiltinTypeSpec.Type.UShort:
7315 return new UShortConstant (t, 0, loc);
7316 case BuiltinTypeSpec.Type.SByte:
7317 return new SByteConstant (t, 0, loc);
7318 case BuiltinTypeSpec.Type.Byte:
7319 return new ByteConstant (t, 0, loc);
7320 case BuiltinTypeSpec.Type.Char:
7321 return new CharConstant (t, '\0', loc);
7322 case BuiltinTypeSpec.Type.Bool:
7323 return new BoolConstant (t, false, loc);
7324 case BuiltinTypeSpec.Type.Decimal:
7325 return new DecimalConstant (t, 0, loc);
7329 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7331 if (t.IsNullableType)
7332 return Nullable.LiftedNull.Create (t, loc);
7337 public override bool ContainsEmitWithAwait ()
7339 return arguments != null && arguments.ContainsEmitWithAwait ();
7343 // Checks whether the type is an interface that has the
7344 // [ComImport, CoClass] attributes and must be treated
7347 public Expression CheckComImport (ResolveContext ec)
7349 if (!type.IsInterface)
7353 // Turn the call into:
7354 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7356 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7357 if (real_class == null)
7360 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7361 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7362 return cast.Resolve (ec);
7365 public override Expression CreateExpressionTree (ResolveContext ec)
7368 if (method == null) {
7369 args = new Arguments (1);
7370 args.Add (new Argument (new TypeOf (type, loc)));
7372 args = Arguments.CreateForExpressionTree (ec,
7373 arguments, new TypeOfMethod (method, loc));
7376 return CreateExpressionFactoryCall (ec, "New", args);
7379 protected override Expression DoResolve (ResolveContext ec)
7381 type = RequestedType.ResolveAsType (ec);
7385 eclass = ExprClass.Value;
7387 if (type.IsPointer) {
7388 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7389 type.GetSignatureForError ());
7393 if (arguments == null) {
7394 Constant c = Constantify (type, RequestedType.Location);
7396 return ReducedExpression.Create (c, this);
7399 if (type.IsDelegate) {
7400 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7403 var tparam = type as TypeParameterSpec;
7404 if (tparam != null) {
7406 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7407 // where type parameter constraint is inflated to struct
7409 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7410 ec.Report.Error (304, loc,
7411 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7412 type.GetSignatureForError ());
7415 if ((arguments != null) && (arguments.Count != 0)) {
7416 ec.Report.Error (417, loc,
7417 "`{0}': cannot provide arguments when creating an instance of a variable type",
7418 type.GetSignatureForError ());
7424 if (type.IsStatic) {
7425 ec.Report.SymbolRelatedToPreviousError (type);
7426 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7430 if (type.IsInterface || type.IsAbstract){
7431 if (!TypeManager.IsGenericType (type)) {
7432 RequestedType = CheckComImport (ec);
7433 if (RequestedType != null)
7434 return RequestedType;
7437 ec.Report.SymbolRelatedToPreviousError (type);
7438 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7443 if (arguments != null) {
7444 arguments.Resolve (ec, out dynamic);
7449 method = ConstructorLookup (ec, type, ref arguments, loc);
7452 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7453 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7459 void DoEmitTypeParameter (EmitContext ec)
7461 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7465 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7466 ec.Emit (OpCodes.Call, ctor_factory);
7470 // This Emit can be invoked in two contexts:
7471 // * As a mechanism that will leave a value on the stack (new object)
7472 // * As one that wont (init struct)
7474 // If we are dealing with a ValueType, we have a few
7475 // situations to deal with:
7477 // * The target is a ValueType, and we have been provided
7478 // the instance (this is easy, we are being assigned).
7480 // * The target of New is being passed as an argument,
7481 // to a boxing operation or a function that takes a
7484 // In this case, we need to create a temporary variable
7485 // that is the argument of New.
7487 // Returns whether a value is left on the stack
7489 // *** Implementation note ***
7491 // To benefit from this optimization, each assignable expression
7492 // has to manually cast to New and call this Emit.
7494 // TODO: It's worth to implement it for arrays and fields
7496 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7498 bool is_value_type = type.IsStructOrEnum;
7499 VariableReference vr = target as VariableReference;
7501 if (target != null && is_value_type && (vr != null || method == null)) {
7502 target.AddressOf (ec, AddressOp.Store);
7503 } else if (vr != null && vr.IsRef) {
7507 if (arguments != null) {
7508 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7509 arguments = arguments.Emit (ec, false, true);
7511 arguments.Emit (ec);
7514 if (is_value_type) {
7515 if (method == null) {
7516 ec.Emit (OpCodes.Initobj, type);
7521 ec.MarkCallEntry (loc);
7522 ec.Emit (OpCodes.Call, method);
7527 if (type is TypeParameterSpec) {
7528 DoEmitTypeParameter (ec);
7532 ec.MarkCallEntry (loc);
7533 ec.Emit (OpCodes.Newobj, method);
7537 public override void Emit (EmitContext ec)
7539 LocalTemporary v = null;
7540 if (method == null && type.IsStructOrEnum) {
7541 // TODO: Use temporary variable from pool
7542 v = new LocalTemporary (type);
7549 public override void EmitStatement (EmitContext ec)
7551 LocalTemporary v = null;
7552 if (method == null && TypeSpec.IsValueType (type)) {
7553 // TODO: Use temporary variable from pool
7554 v = new LocalTemporary (type);
7558 ec.Emit (OpCodes.Pop);
7561 public override void FlowAnalysis (FlowAnalysisContext fc)
7563 if (arguments != null)
7564 arguments.FlowAnalysis (fc);
7567 public void AddressOf (EmitContext ec, AddressOp mode)
7569 EmitAddressOf (ec, mode);
7572 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7574 LocalTemporary value_target = new LocalTemporary (type);
7576 if (type is TypeParameterSpec) {
7577 DoEmitTypeParameter (ec);
7578 value_target.Store (ec);
7579 value_target.AddressOf (ec, mode);
7580 return value_target;
7583 value_target.AddressOf (ec, AddressOp.Store);
7585 if (method == null) {
7586 ec.Emit (OpCodes.Initobj, type);
7588 if (arguments != null)
7589 arguments.Emit (ec);
7591 ec.Emit (OpCodes.Call, method);
7594 value_target.AddressOf (ec, mode);
7595 return value_target;
7598 protected override void CloneTo (CloneContext clonectx, Expression t)
7600 New target = (New) t;
7602 target.RequestedType = RequestedType.Clone (clonectx);
7603 if (arguments != null){
7604 target.arguments = arguments.Clone (clonectx);
7608 public override SLE.Expression MakeExpression (BuilderContext ctx)
7611 return base.MakeExpression (ctx);
7613 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7617 public override object Accept (StructuralVisitor visitor)
7619 return visitor.Visit (this);
7624 // Array initializer expression, the expression is allowed in
7625 // variable or field initialization only which makes it tricky as
7626 // the type has to be infered based on the context either from field
7627 // type or variable type (think of multiple declarators)
7629 public class ArrayInitializer : Expression
7631 List<Expression> elements;
7632 BlockVariable variable;
7634 public ArrayInitializer (List<Expression> init, Location loc)
7640 public ArrayInitializer (int count, Location loc)
7641 : this (new List<Expression> (count), loc)
7645 public ArrayInitializer (Location loc)
7653 get { return elements.Count; }
7656 public List<Expression> Elements {
7662 public Expression this [int index] {
7664 return elements [index];
7668 public BlockVariable VariableDeclaration {
7679 public void Add (Expression expr)
7681 elements.Add (expr);
7684 public override bool ContainsEmitWithAwait ()
7686 throw new NotSupportedException ();
7689 public override Expression CreateExpressionTree (ResolveContext ec)
7691 throw new NotSupportedException ("ET");
7694 protected override void CloneTo (CloneContext clonectx, Expression t)
7696 var target = (ArrayInitializer) t;
7698 target.elements = new List<Expression> (elements.Count);
7699 foreach (var element in elements)
7700 target.elements.Add (element.Clone (clonectx));
7703 protected override Expression DoResolve (ResolveContext rc)
7705 var current_field = rc.CurrentMemberDefinition as FieldBase;
7706 TypeExpression type;
7707 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7708 type = new TypeExpression (current_field.MemberType, current_field.Location);
7709 } else if (variable != null) {
7710 if (variable.TypeExpression is VarExpr) {
7711 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7712 return EmptyExpression.Null;
7715 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7717 throw new NotImplementedException ("Unexpected array initializer context");
7720 return new ArrayCreation (type, this).Resolve (rc);
7723 public override void Emit (EmitContext ec)
7725 throw new InternalErrorException ("Missing Resolve call");
7728 public override void FlowAnalysis (FlowAnalysisContext fc)
7730 throw new InternalErrorException ("Missing Resolve call");
7733 public override object Accept (StructuralVisitor visitor)
7735 return visitor.Visit (this);
7740 /// 14.5.10.2: Represents an array creation expression.
7744 /// There are two possible scenarios here: one is an array creation
7745 /// expression that specifies the dimensions and optionally the
7746 /// initialization data and the other which does not need dimensions
7747 /// specified but where initialization data is mandatory.
7749 public class ArrayCreation : Expression
7751 FullNamedExpression requested_base_type;
7752 ArrayInitializer initializers;
7755 // The list of Argument types.
7756 // This is used to construct the `newarray' or constructor signature
7758 protected List<Expression> arguments;
7760 protected TypeSpec array_element_type;
7762 protected int dimensions;
7763 protected readonly ComposedTypeSpecifier rank;
7764 Expression first_emit;
7765 LocalTemporary first_emit_temp;
7767 protected List<Expression> array_data;
7769 Dictionary<int, int> bounds;
7772 // The number of constants in array initializers
7773 int const_initializers_count;
7774 bool only_constant_initializers;
7776 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7777 : this (requested_base_type, rank, initializers, l)
7779 arguments = new List<Expression> (exprs);
7780 num_arguments = arguments.Count;
7784 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7786 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7788 this.requested_base_type = requested_base_type;
7790 this.initializers = initializers;
7794 num_arguments = rank.Dimension;
7798 // For compiler generated single dimensional arrays only
7800 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7801 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7806 // For expressions like int[] foo = { 1, 2, 3 };
7808 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7809 : this (requested_base_type, null, initializers, initializers.Location)
7813 public ComposedTypeSpecifier Rank {
7819 public FullNamedExpression TypeExpression {
7821 return this.requested_base_type;
7825 public ArrayInitializer Initializers {
7827 return this.initializers;
7831 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7833 if (initializers != null && bounds == null) {
7835 // We use this to store all the data values in the order in which we
7836 // will need to store them in the byte blob later
7838 array_data = new List<Expression> (probe.Count);
7839 bounds = new Dictionary<int, int> ();
7842 if (specified_dims) {
7843 Expression a = arguments [idx];
7848 a = ConvertExpressionToArrayIndex (ec, a);
7854 if (initializers != null) {
7855 Constant c = a as Constant;
7856 if (c == null && a is ArrayIndexCast)
7857 c = ((ArrayIndexCast) a).Child as Constant;
7860 ec.Report.Error (150, a.Location, "A constant value is expected");
7866 value = System.Convert.ToInt32 (c.GetValue ());
7868 ec.Report.Error (150, a.Location, "A constant value is expected");
7872 // TODO: probe.Count does not fit ulong in
7873 if (value != probe.Count) {
7874 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7878 bounds[idx] = value;
7882 if (initializers == null)
7885 for (int i = 0; i < probe.Count; ++i) {
7887 if (o is ArrayInitializer) {
7888 var sub_probe = o as ArrayInitializer;
7889 if (idx + 1 >= dimensions){
7890 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7894 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7895 if (!bounds.ContainsKey(idx + 1))
7896 bounds[idx + 1] = sub_probe.Count;
7898 if (bounds[idx + 1] != sub_probe.Count) {
7899 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7903 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7906 } else if (child_bounds > 1) {
7907 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7909 Expression element = ResolveArrayElement (ec, o);
7910 if (element == null)
7913 // Initializers with the default values can be ignored
7914 Constant c = element as Constant;
7916 if (!c.IsDefaultInitializer (array_element_type)) {
7917 ++const_initializers_count;
7920 only_constant_initializers = false;
7923 array_data.Add (element);
7930 public override bool ContainsEmitWithAwait ()
7932 foreach (var arg in arguments) {
7933 if (arg.ContainsEmitWithAwait ())
7937 return InitializersContainAwait ();
7940 public override Expression CreateExpressionTree (ResolveContext ec)
7944 if (array_data == null) {
7945 args = new Arguments (arguments.Count + 1);
7946 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7947 foreach (Expression a in arguments)
7948 args.Add (new Argument (a.CreateExpressionTree (ec)));
7950 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7953 if (dimensions > 1) {
7954 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7958 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7959 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7960 if (array_data != null) {
7961 for (int i = 0; i < array_data.Count; ++i) {
7962 Expression e = array_data [i];
7963 args.Add (new Argument (e.CreateExpressionTree (ec)));
7967 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7970 void UpdateIndices (ResolveContext rc)
7973 for (var probe = initializers; probe != null;) {
7974 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7976 bounds[i++] = probe.Count;
7978 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7979 probe = (ArrayInitializer) probe[0];
7980 } else if (dimensions > i) {
7988 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7990 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7993 public override void FlowAnalysis (FlowAnalysisContext fc)
7995 foreach (var arg in arguments)
7996 arg.FlowAnalysis (fc);
7998 if (array_data != null) {
7999 foreach (var ad in array_data)
8000 ad.FlowAnalysis (fc);
8004 bool InitializersContainAwait ()
8006 if (array_data == null)
8009 foreach (var expr in array_data) {
8010 if (expr.ContainsEmitWithAwait ())
8017 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8019 element = element.Resolve (ec);
8020 if (element == null)
8023 if (element is CompoundAssign.TargetExpression) {
8024 if (first_emit != null)
8025 throw new InternalErrorException ("Can only handle one mutator at a time");
8026 first_emit = element;
8027 element = first_emit_temp = new LocalTemporary (element.Type);
8030 return Convert.ImplicitConversionRequired (
8031 ec, element, array_element_type, loc);
8034 protected bool ResolveInitializers (ResolveContext ec)
8037 only_constant_initializers = true;
8040 if (arguments != null) {
8042 for (int i = 0; i < arguments.Count; ++i) {
8043 res &= CheckIndices (ec, initializers, i, true, dimensions);
8044 if (initializers != null)
8051 arguments = new List<Expression> ();
8053 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8062 // Resolved the type of the array
8064 bool ResolveArrayType (ResolveContext ec)
8069 FullNamedExpression array_type_expr;
8070 if (num_arguments > 0) {
8071 array_type_expr = new ComposedCast (requested_base_type, rank);
8073 array_type_expr = requested_base_type;
8076 type = array_type_expr.ResolveAsType (ec);
8077 if (array_type_expr == null)
8080 var ac = type as ArrayContainer;
8082 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8086 array_element_type = ac.Element;
8087 dimensions = ac.Rank;
8092 protected override Expression DoResolve (ResolveContext ec)
8097 if (!ResolveArrayType (ec))
8101 // validate the initializers and fill in any missing bits
8103 if (!ResolveInitializers (ec))
8106 eclass = ExprClass.Value;
8110 byte [] MakeByteBlob ()
8115 int count = array_data.Count;
8117 TypeSpec element_type = array_element_type;
8118 if (element_type.IsEnum)
8119 element_type = EnumSpec.GetUnderlyingType (element_type);
8121 factor = BuiltinTypeSpec.GetSize (element_type);
8123 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8125 data = new byte [(count * factor + 3) & ~3];
8128 for (int i = 0; i < count; ++i) {
8129 var c = array_data[i] as Constant;
8135 object v = c.GetValue ();
8137 switch (element_type.BuiltinType) {
8138 case BuiltinTypeSpec.Type.Long:
8139 long lval = (long) v;
8141 for (int j = 0; j < factor; ++j) {
8142 data[idx + j] = (byte) (lval & 0xFF);
8146 case BuiltinTypeSpec.Type.ULong:
8147 ulong ulval = (ulong) v;
8149 for (int j = 0; j < factor; ++j) {
8150 data[idx + j] = (byte) (ulval & 0xFF);
8151 ulval = (ulval >> 8);
8154 case BuiltinTypeSpec.Type.Float:
8155 var fval = SingleConverter.SingleToInt32Bits((float) v);
8157 data[idx] = (byte) (fval & 0xff);
8158 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8159 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8160 data[idx + 3] = (byte) (fval >> 24);
8162 case BuiltinTypeSpec.Type.Double:
8163 element = BitConverter.GetBytes ((double) v);
8165 for (int j = 0; j < factor; ++j)
8166 data[idx + j] = element[j];
8168 // FIXME: Handle the ARM float format.
8169 if (!BitConverter.IsLittleEndian)
8170 System.Array.Reverse (data, idx, 8);
8172 case BuiltinTypeSpec.Type.Char:
8173 int chval = (int) ((char) v);
8175 data[idx] = (byte) (chval & 0xff);
8176 data[idx + 1] = (byte) (chval >> 8);
8178 case BuiltinTypeSpec.Type.Short:
8179 int sval = (int) ((short) v);
8181 data[idx] = (byte) (sval & 0xff);
8182 data[idx + 1] = (byte) (sval >> 8);
8184 case BuiltinTypeSpec.Type.UShort:
8185 int usval = (int) ((ushort) v);
8187 data[idx] = (byte) (usval & 0xff);
8188 data[idx + 1] = (byte) (usval >> 8);
8190 case BuiltinTypeSpec.Type.Int:
8193 data[idx] = (byte) (val & 0xff);
8194 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8195 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8196 data[idx + 3] = (byte) (val >> 24);
8198 case BuiltinTypeSpec.Type.UInt:
8199 uint uval = (uint) v;
8201 data[idx] = (byte) (uval & 0xff);
8202 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8203 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8204 data[idx + 3] = (byte) (uval >> 24);
8206 case BuiltinTypeSpec.Type.SByte:
8207 data[idx] = (byte) (sbyte) v;
8209 case BuiltinTypeSpec.Type.Byte:
8210 data[idx] = (byte) v;
8212 case BuiltinTypeSpec.Type.Bool:
8213 data[idx] = (byte) ((bool) v ? 1 : 0);
8215 case BuiltinTypeSpec.Type.Decimal:
8216 int[] bits = Decimal.GetBits ((decimal) v);
8219 // FIXME: For some reason, this doesn't work on the MS runtime.
8220 int[] nbits = new int[4];
8226 for (int j = 0; j < 4; j++) {
8227 data[p++] = (byte) (nbits[j] & 0xff);
8228 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8229 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8230 data[p++] = (byte) (nbits[j] >> 24);
8234 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8243 #if NET_4_0 || MOBILE_DYNAMIC
8244 public override SLE.Expression MakeExpression (BuilderContext ctx)
8247 return base.MakeExpression (ctx);
8249 var initializers = new SLE.Expression [array_data.Count];
8250 for (var i = 0; i < initializers.Length; i++) {
8251 if (array_data [i] == null)
8252 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8254 initializers [i] = array_data [i].MakeExpression (ctx);
8257 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8263 // Emits the initializers for the array
8265 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8267 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8272 // First, the static data
8274 byte [] data = MakeByteBlob ();
8275 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8277 if (stackArray == null) {
8278 ec.Emit (OpCodes.Dup);
8280 stackArray.Emit (ec);
8283 ec.Emit (OpCodes.Ldtoken, fb);
8284 ec.Emit (OpCodes.Call, m);
8289 // Emits pieces of the array that can not be computed at compile
8290 // time (variables and string locations).
8292 // This always expect the top value on the stack to be the array
8294 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8296 int dims = bounds.Count;
8297 var current_pos = new int [dims];
8299 for (int i = 0; i < array_data.Count; i++){
8301 Expression e = array_data [i];
8302 var c = e as Constant;
8304 // Constant can be initialized via StaticInitializer
8305 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8309 if (stackArray != null) {
8310 if (e.ContainsEmitWithAwait ()) {
8311 e = e.EmitToField (ec);
8314 stackArray.EmitLoad (ec);
8316 ec.Emit (OpCodes.Dup);
8319 for (int idx = 0; idx < dims; idx++)
8320 ec.EmitInt (current_pos [idx]);
8323 // If we are dealing with a struct, get the
8324 // address of it, so we can store it.
8326 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8327 ec.Emit (OpCodes.Ldelema, etype);
8331 ec.EmitArrayStore ((ArrayContainer) type);
8337 for (int j = dims - 1; j >= 0; j--){
8339 if (current_pos [j] < bounds [j])
8341 current_pos [j] = 0;
8345 if (stackArray != null)
8346 stackArray.PrepareCleanup (ec);
8349 public override void Emit (EmitContext ec)
8351 var await_field = EmitToFieldSource (ec);
8352 if (await_field != null)
8353 await_field.Emit (ec);
8356 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8358 if (first_emit != null) {
8359 first_emit.Emit (ec);
8360 first_emit_temp.Store (ec);
8363 StackFieldExpr await_stack_field;
8364 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8365 await_stack_field = ec.GetTemporaryField (type);
8368 await_stack_field = null;
8371 EmitExpressionsList (ec, arguments);
8373 ec.EmitArrayNew ((ArrayContainer) type);
8375 if (initializers == null)
8376 return await_stack_field;
8378 if (await_stack_field != null)
8379 await_stack_field.EmitAssignFromStack (ec);
8383 // Emit static initializer for arrays which contain more than 2 items and
8384 // the static initializer will initialize at least 25% of array values or there
8385 // is more than 10 items to be initialized
8387 // NOTE: const_initializers_count does not contain default constant values.
8389 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8390 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8391 EmitStaticInitializers (ec, await_stack_field);
8393 if (!only_constant_initializers)
8394 EmitDynamicInitializers (ec, false, await_stack_field);
8398 EmitDynamicInitializers (ec, true, await_stack_field);
8401 if (first_emit_temp != null)
8402 first_emit_temp.Release (ec);
8404 return await_stack_field;
8407 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8409 // no multi dimensional or jagged arrays
8410 if (arguments.Count != 1 || array_element_type.IsArray) {
8411 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8415 // No array covariance, except for array -> object
8416 if (type != targetType) {
8417 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8418 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8422 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8423 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8428 // Single dimensional array of 0 size
8429 if (array_data == null) {
8430 IntConstant ic = arguments[0] as IntConstant;
8431 if (ic == null || !ic.IsDefaultValue) {
8432 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8440 enc.Encode (array_data.Count);
8441 foreach (var element in array_data) {
8442 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8446 protected override void CloneTo (CloneContext clonectx, Expression t)
8448 ArrayCreation target = (ArrayCreation) t;
8450 if (requested_base_type != null)
8451 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8453 if (arguments != null){
8454 target.arguments = new List<Expression> (arguments.Count);
8455 foreach (Expression e in arguments)
8456 target.arguments.Add (e.Clone (clonectx));
8459 if (initializers != null)
8460 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8463 public override object Accept (StructuralVisitor visitor)
8465 return visitor.Visit (this);
8470 // Represents an implicitly typed array epxression
8472 class ImplicitlyTypedArrayCreation : ArrayCreation
8474 TypeInferenceContext best_type_inference;
8476 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8477 : base (null, rank, initializers, loc)
8481 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8482 : base (null, initializers, loc)
8486 protected override Expression DoResolve (ResolveContext ec)
8491 dimensions = rank.Dimension;
8493 best_type_inference = new TypeInferenceContext ();
8495 if (!ResolveInitializers (ec))
8498 best_type_inference.FixAllTypes (ec);
8499 array_element_type = best_type_inference.InferredTypeArguments[0];
8500 best_type_inference = null;
8502 if (array_element_type == null ||
8503 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8504 arguments.Count != rank.Dimension) {
8505 ec.Report.Error (826, loc,
8506 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8511 // At this point we found common base type for all initializer elements
8512 // but we have to be sure that all static initializer elements are of
8515 UnifyInitializerElement (ec);
8517 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8518 eclass = ExprClass.Value;
8523 // Converts static initializer only
8525 void UnifyInitializerElement (ResolveContext ec)
8527 for (int i = 0; i < array_data.Count; ++i) {
8528 Expression e = array_data[i];
8530 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8534 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8536 element = element.Resolve (ec);
8537 if (element != null)
8538 best_type_inference.AddCommonTypeBound (element.Type);
8544 sealed class CompilerGeneratedThis : This
8546 public CompilerGeneratedThis (TypeSpec type, Location loc)
8552 protected override Expression DoResolve (ResolveContext rc)
8554 eclass = ExprClass.Variable;
8556 var block = rc.CurrentBlock;
8557 if (block != null) {
8558 var top = block.ParametersBlock.TopBlock;
8559 if (top.ThisVariable != null)
8560 variable_info = top.ThisVariable.VariableInfo;
8567 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8569 return DoResolve (rc);
8572 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8579 /// Represents the `this' construct
8582 public class This : VariableReference
8584 sealed class ThisVariable : ILocalVariable
8586 public static readonly ILocalVariable Instance = new ThisVariable ();
8588 public void Emit (EmitContext ec)
8593 public void EmitAssign (EmitContext ec)
8595 throw new InvalidOperationException ();
8598 public void EmitAddressOf (EmitContext ec)
8604 protected VariableInfo variable_info;
8606 public This (Location loc)
8613 public override string Name {
8614 get { return "this"; }
8617 public override bool IsLockedByStatement {
8625 public override bool IsRef {
8626 get { return type.IsStruct; }
8629 public override bool IsSideEffectFree {
8635 protected override ILocalVariable Variable {
8636 get { return ThisVariable.Instance; }
8639 public override VariableInfo VariableInfo {
8640 get { return variable_info; }
8643 public override bool IsFixed {
8644 get { return false; }
8649 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8652 // It's null for all cases when we don't need to check `this'
8653 // definitive assignment
8655 if (variable_info == null)
8658 if (fc.IsDefinitelyAssigned (variable_info))
8661 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8664 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8666 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8667 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8668 } else if (ec.CurrentAnonymousMethod != null) {
8669 ec.Report.Error (1673, loc,
8670 "Anonymous methods inside structs cannot access instance members of `this'. " +
8671 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8673 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8677 public override void FlowAnalysis (FlowAnalysisContext fc)
8679 CheckStructThisDefiniteAssignment (fc);
8682 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8687 AnonymousMethodStorey storey = ae.Storey;
8688 return storey != null ? storey.HoistedThis : null;
8691 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8693 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8696 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8699 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8705 public virtual void ResolveBase (ResolveContext ec)
8707 eclass = ExprClass.Variable;
8708 type = ec.CurrentType;
8710 if (!IsThisAvailable (ec, false)) {
8711 Error_ThisNotAvailable (ec);
8715 var block = ec.CurrentBlock;
8716 if (block != null) {
8717 var top = block.ParametersBlock.TopBlock;
8718 if (top.ThisVariable != null)
8719 variable_info = top.ThisVariable.VariableInfo;
8721 AnonymousExpression am = ec.CurrentAnonymousMethod;
8722 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8724 // Hoisted this is almost like hoisted variable but not exactly. When
8725 // there is no variable hoisted we can simply emit an instance method
8726 // without lifting this into a storey. Unfotunatelly this complicates
8727 // things in other cases because we don't know where this will be hoisted
8728 // until top-level block is fully resolved
8730 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8731 am.SetHasThisAccess ();
8736 protected override Expression DoResolve (ResolveContext ec)
8742 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8744 if (eclass == ExprClass.Unresolved)
8748 if (right_side == EmptyExpression.UnaryAddress)
8749 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8750 else if (right_side == EmptyExpression.OutAccess)
8751 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8753 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8759 public override int GetHashCode()
8761 throw new NotImplementedException ();
8764 public override bool Equals (object obj)
8766 This t = obj as This;
8773 protected override void CloneTo (CloneContext clonectx, Expression t)
8778 public override void SetHasAddressTaken ()
8783 public override object Accept (StructuralVisitor visitor)
8785 return visitor.Visit (this);
8790 /// Represents the `__arglist' construct
8792 public class ArglistAccess : Expression
8794 public ArglistAccess (Location loc)
8799 protected override void CloneTo (CloneContext clonectx, Expression target)
8804 public override bool ContainsEmitWithAwait ()
8809 public override Expression CreateExpressionTree (ResolveContext ec)
8811 throw new NotSupportedException ("ET");
8814 protected override Expression DoResolve (ResolveContext ec)
8816 eclass = ExprClass.Variable;
8817 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8819 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8820 ec.Report.Error (190, loc,
8821 "The __arglist construct is valid only within a variable argument method");
8827 public override void Emit (EmitContext ec)
8829 ec.Emit (OpCodes.Arglist);
8832 public override object Accept (StructuralVisitor visitor)
8834 return visitor.Visit (this);
8839 /// Represents the `__arglist (....)' construct
8841 public class Arglist : Expression
8843 Arguments arguments;
8845 public Arglist (Location loc)
8850 public Arglist (Arguments args, Location l)
8856 public Arguments Arguments {
8862 public MetaType[] ArgumentTypes {
8864 if (arguments == null)
8865 return MetaType.EmptyTypes;
8867 var retval = new MetaType[arguments.Count];
8868 for (int i = 0; i < retval.Length; i++)
8869 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8875 public override bool ContainsEmitWithAwait ()
8877 throw new NotImplementedException ();
8880 public override Expression CreateExpressionTree (ResolveContext ec)
8882 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8886 protected override Expression DoResolve (ResolveContext ec)
8888 eclass = ExprClass.Variable;
8889 type = InternalType.Arglist;
8890 if (arguments != null) {
8891 bool dynamic; // Can be ignored as there is always only 1 overload
8892 arguments.Resolve (ec, out dynamic);
8898 public override void Emit (EmitContext ec)
8900 if (arguments != null)
8901 arguments.Emit (ec);
8904 protected override void CloneTo (CloneContext clonectx, Expression t)
8906 Arglist target = (Arglist) t;
8908 if (arguments != null)
8909 target.arguments = arguments.Clone (clonectx);
8912 public override object Accept (StructuralVisitor visitor)
8914 return visitor.Visit (this);
8918 public class RefValueExpr : ShimExpression, IAssignMethod
8920 FullNamedExpression texpr;
8922 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8929 public FullNamedExpression TypeExpression {
8935 public override bool ContainsEmitWithAwait ()
8940 protected override Expression DoResolve (ResolveContext rc)
8942 expr = expr.Resolve (rc);
8943 type = texpr.ResolveAsType (rc);
8944 if (expr == null || type == null)
8947 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8948 eclass = ExprClass.Value;
8952 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8954 return DoResolve (rc);
8957 public override void Emit (EmitContext ec)
8960 ec.Emit (OpCodes.Refanyval, type);
8961 ec.EmitLoadFromPtr (type);
8964 public void Emit (EmitContext ec, bool leave_copy)
8966 throw new NotImplementedException ();
8969 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8972 ec.Emit (OpCodes.Refanyval, type);
8975 LocalTemporary temporary = null;
8977 ec.Emit (OpCodes.Dup);
8978 temporary = new LocalTemporary (source.Type);
8979 temporary.Store (ec);
8982 ec.EmitStoreFromPtr (type);
8984 if (temporary != null) {
8985 temporary.Emit (ec);
8986 temporary.Release (ec);
8990 public override object Accept (StructuralVisitor visitor)
8992 return visitor.Visit (this);
8996 public class RefTypeExpr : ShimExpression
8998 public RefTypeExpr (Expression expr, Location loc)
9004 protected override Expression DoResolve (ResolveContext rc)
9006 expr = expr.Resolve (rc);
9010 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9014 type = rc.BuiltinTypes.Type;
9015 eclass = ExprClass.Value;
9019 public override void Emit (EmitContext ec)
9022 ec.Emit (OpCodes.Refanytype);
9023 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9025 ec.Emit (OpCodes.Call, m);
9028 public override object Accept (StructuralVisitor visitor)
9030 return visitor.Visit (this);
9034 public class MakeRefExpr : ShimExpression
9036 public MakeRefExpr (Expression expr, Location loc)
9042 public override bool ContainsEmitWithAwait ()
9044 throw new NotImplementedException ();
9047 protected override Expression DoResolve (ResolveContext rc)
9049 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9050 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9051 eclass = ExprClass.Value;
9055 public override void Emit (EmitContext ec)
9057 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9058 ec.Emit (OpCodes.Mkrefany, expr.Type);
9061 public override object Accept (StructuralVisitor visitor)
9063 return visitor.Visit (this);
9068 /// Implements the typeof operator
9070 public class TypeOf : Expression {
9071 FullNamedExpression QueriedType;
9074 public TypeOf (FullNamedExpression queried_type, Location l)
9076 QueriedType = queried_type;
9081 // Use this constructor for any compiler generated typeof expression
9083 public TypeOf (TypeSpec type, Location loc)
9085 this.typearg = type;
9091 public override bool IsSideEffectFree {
9097 public TypeSpec TypeArgument {
9103 public FullNamedExpression TypeExpression {
9112 protected override void CloneTo (CloneContext clonectx, Expression t)
9114 TypeOf target = (TypeOf) t;
9115 if (QueriedType != null)
9116 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9119 public override bool ContainsEmitWithAwait ()
9124 public override Expression CreateExpressionTree (ResolveContext ec)
9126 Arguments args = new Arguments (2);
9127 args.Add (new Argument (this));
9128 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9129 return CreateExpressionFactoryCall (ec, "Constant", args);
9132 protected override Expression DoResolve (ResolveContext ec)
9134 if (eclass != ExprClass.Unresolved)
9137 if (typearg == null) {
9139 // Pointer types are allowed without explicit unsafe, they are just tokens
9141 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9142 typearg = QueriedType.ResolveAsType (ec, true);
9145 if (typearg == null)
9148 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9149 ec.Report.Error (1962, QueriedType.Location,
9150 "The typeof operator cannot be used on the dynamic type");
9154 type = ec.BuiltinTypes.Type;
9156 // Even though what is returned is a type object, it's treated as a value by the compiler.
9157 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9158 eclass = ExprClass.Value;
9162 static bool ContainsDynamicType (TypeSpec type)
9164 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9167 var element_container = type as ElementTypeSpec;
9168 if (element_container != null)
9169 return ContainsDynamicType (element_container.Element);
9171 foreach (var t in type.TypeArguments) {
9172 if (ContainsDynamicType (t)) {
9180 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9182 // Target type is not System.Type therefore must be object
9183 // and we need to use different encoding sequence
9184 if (targetType != type)
9187 if (typearg is InflatedTypeSpec) {
9190 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9191 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9192 typearg.GetSignatureForError ());
9196 gt = gt.DeclaringType;
9197 } while (gt != null);
9200 if (ContainsDynamicType (typearg)) {
9201 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9205 enc.EncodeTypeName (typearg);
9208 public override void Emit (EmitContext ec)
9210 ec.Emit (OpCodes.Ldtoken, typearg);
9211 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9213 ec.Emit (OpCodes.Call, m);
9216 public override object Accept (StructuralVisitor visitor)
9218 return visitor.Visit (this);
9222 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9224 public TypeOfMethod (MethodSpec method, Location loc)
9225 : base (method, loc)
9229 protected override Expression DoResolve (ResolveContext ec)
9231 if (member.IsConstructor) {
9232 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9234 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9240 return base.DoResolve (ec);
9243 public override void Emit (EmitContext ec)
9245 ec.Emit (OpCodes.Ldtoken, member);
9248 ec.Emit (OpCodes.Castclass, type);
9251 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9253 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9256 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9258 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9262 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9264 protected readonly T member;
9266 protected TypeOfMember (T member, Location loc)
9268 this.member = member;
9272 public override bool IsSideEffectFree {
9278 public override bool ContainsEmitWithAwait ()
9283 public override Expression CreateExpressionTree (ResolveContext ec)
9285 Arguments args = new Arguments (2);
9286 args.Add (new Argument (this));
9287 args.Add (new Argument (new TypeOf (type, loc)));
9288 return CreateExpressionFactoryCall (ec, "Constant", args);
9291 protected override Expression DoResolve (ResolveContext ec)
9293 eclass = ExprClass.Value;
9297 public override void Emit (EmitContext ec)
9299 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9300 PredefinedMember<MethodSpec> p;
9302 p = GetTypeFromHandleGeneric (ec);
9303 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9305 p = GetTypeFromHandle (ec);
9308 var mi = p.Resolve (loc);
9310 ec.Emit (OpCodes.Call, mi);
9313 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9314 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9317 sealed class TypeOfField : TypeOfMember<FieldSpec>
9319 public TypeOfField (FieldSpec field, Location loc)
9324 protected override Expression DoResolve (ResolveContext ec)
9326 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9330 return base.DoResolve (ec);
9333 public override void Emit (EmitContext ec)
9335 ec.Emit (OpCodes.Ldtoken, member);
9339 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9341 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9344 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9346 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9351 /// Implements the sizeof expression
9353 public class SizeOf : Expression {
9354 readonly Expression texpr;
9355 TypeSpec type_queried;
9357 public SizeOf (Expression queried_type, Location l)
9359 this.texpr = queried_type;
9363 public override bool IsSideEffectFree {
9369 public Expression TypeExpression {
9375 public override bool ContainsEmitWithAwait ()
9380 public override Expression CreateExpressionTree (ResolveContext ec)
9382 Error_PointerInsideExpressionTree (ec);
9386 protected override Expression DoResolve (ResolveContext ec)
9388 type_queried = texpr.ResolveAsType (ec);
9389 if (type_queried == null)
9392 if (type_queried.IsEnum)
9393 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9395 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9397 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9400 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9405 ec.Report.Error (233, loc,
9406 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9407 type_queried.GetSignatureForError ());
9410 type = ec.BuiltinTypes.Int;
9411 eclass = ExprClass.Value;
9415 public override void Emit (EmitContext ec)
9417 ec.Emit (OpCodes.Sizeof, type_queried);
9420 protected override void CloneTo (CloneContext clonectx, Expression t)
9424 public override object Accept (StructuralVisitor visitor)
9426 return visitor.Visit (this);
9431 /// Implements the qualified-alias-member (::) expression.
9433 public class QualifiedAliasMember : MemberAccess
9435 readonly string alias;
9436 public static readonly string GlobalAlias = "global";
9438 public QualifiedAliasMember (string alias, string identifier, Location l)
9439 : base (null, identifier, l)
9444 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9445 : base (null, identifier, targs, l)
9450 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9451 : base (null, identifier, arity, l)
9456 public string Alias {
9462 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9464 if (alias == GlobalAlias)
9465 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9467 int errors = mc.Module.Compiler.Report.Errors;
9468 var expr = mc.LookupNamespaceAlias (alias);
9470 if (errors == mc.Module.Compiler.Report.Errors)
9471 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9479 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9481 expr = CreateExpressionFromAlias (mc);
9485 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9488 protected override Expression DoResolve (ResolveContext rc)
9490 return ResolveAsTypeOrNamespace (rc, false);
9493 public override string GetSignatureForError ()
9496 if (targs != null) {
9497 name = Name + "<" + targs.GetSignatureForError () + ">";
9500 return alias + "::" + name;
9503 public override bool HasConditionalAccess ()
9508 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9510 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9511 rc.Module.Compiler.Report.Error (687, loc,
9512 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9513 GetSignatureForError ());
9518 return DoResolve (rc);
9521 protected override void CloneTo (CloneContext clonectx, Expression t)
9526 public override object Accept (StructuralVisitor visitor)
9528 return visitor.Visit (this);
9533 /// Implements the member access expression
9535 public class MemberAccess : ATypeNameExpression
9537 protected Expression expr;
9539 public MemberAccess (Expression expr, string id)
9540 : base (id, expr.Location)
9545 public MemberAccess (Expression expr, string identifier, Location loc)
9546 : base (identifier, loc)
9551 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9552 : base (identifier, args, loc)
9557 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9558 : base (identifier, arity, loc)
9563 public Expression LeftExpression {
9569 public override Location StartLocation {
9571 return expr == null ? loc : expr.StartLocation;
9575 protected override Expression DoResolve (ResolveContext rc)
9577 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9579 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9584 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9586 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9588 if (e is TypeExpr) {
9589 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9594 e = e.ResolveLValue (rc, rhs);
9599 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9601 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9602 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9604 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9607 public override bool HasConditionalAccess ()
9609 return LeftExpression.HasConditionalAccess ();
9612 public static bool IsValidDotExpression (TypeSpec type)
9614 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9615 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9617 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9620 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9622 var sn = expr as SimpleName;
9623 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9626 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9629 // Resolve expression which does have type set as we need expression type
9630 // with disable flow analysis as we don't know whether left side expression
9631 // is used as variable or type
9633 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9634 expr = expr.Resolve (rc);
9635 } else if (expr is TypeParameterExpr) {
9636 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9640 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9641 expr = expr.Resolve (rc, flags);
9648 var ns = expr as NamespaceExpression;
9650 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9652 if (retval == null) {
9653 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
9657 if (HasTypeArguments)
9658 return new GenericTypeExpr (retval.Type, targs, loc);
9664 TypeSpec expr_type = expr.Type;
9665 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9666 me = expr as MemberExpr;
9668 me.ResolveInstanceExpression (rc, null);
9670 Arguments args = new Arguments (1);
9671 args.Add (new Argument (expr));
9672 return new DynamicMemberBinder (Name, args, loc);
9675 var cma = this as ConditionalMemberAccess;
9677 if (!IsNullPropagatingValid (expr.Type)) {
9678 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9682 if (expr_type.IsNullableType) {
9683 expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
9684 expr_type = expr.Type;
9688 if (!IsValidDotExpression (expr_type)) {
9689 Error_OperatorCannotBeApplied (rc, expr_type);
9693 var lookup_arity = Arity;
9694 bool errorMode = false;
9695 Expression member_lookup;
9697 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9698 if (member_lookup == null) {
9700 // Try to look for extension method when member lookup failed
9702 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9703 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
9704 if (methods != null) {
9705 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9706 if (HasTypeArguments) {
9707 if (!targs.Resolve (rc))
9710 emg.SetTypeArguments (rc, targs);
9714 emg.ConditionalAccess = true;
9716 // TODO: it should really skip the checks bellow
9717 return emg.Resolve (rc);
9723 if (member_lookup == null) {
9724 var dep = expr_type.GetMissingDependencies ();
9726 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9727 } else if (expr is TypeExpr) {
9728 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9730 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9736 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9737 // Leave it to overload resolution to report correct error
9738 } else if (!(member_lookup is TypeExpr)) {
9739 // TODO: rc.SymbolRelatedToPreviousError
9740 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9745 if (member_lookup != null)
9749 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9753 TypeExpr texpr = member_lookup as TypeExpr;
9754 if (texpr != null) {
9755 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9756 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9757 Name, texpr.GetSignatureForError ());
9760 if (!texpr.Type.IsAccessible (rc)) {
9761 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9762 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9766 if (HasTypeArguments) {
9767 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9770 return member_lookup;
9773 me = member_lookup as MemberExpr;
9775 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9780 me.ConditionalAccess = true;
9783 me = me.ResolveMemberAccess (rc, expr, sn);
9786 if (!targs.Resolve (rc))
9789 me.SetTypeArguments (rc, targs);
9795 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9797 FullNamedExpression fexpr = expr as FullNamedExpression;
9798 if (fexpr == null) {
9799 expr.ResolveAsType (rc);
9803 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9805 if (expr_resolved == null)
9808 var ns = expr_resolved as NamespaceExpression;
9810 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9812 if (retval == null) {
9813 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
9814 } else if (Arity > 0) {
9815 if (HasTypeArguments) {
9816 retval = new GenericTypeExpr (retval.Type, targs, loc);
9817 if (retval.ResolveAsType (rc) == null)
9820 if (!allowUnboundTypeArguments)
9821 Error_OpenGenericTypeIsNotAllowed (rc);
9823 retval = new GenericOpenTypeExpr (retval.Type, loc);
9830 var tnew_expr = expr_resolved.ResolveAsType (rc);
9831 if (tnew_expr == null)
9834 TypeSpec expr_type = tnew_expr;
9835 if (TypeManager.IsGenericParameter (expr_type)) {
9836 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9837 tnew_expr.GetSignatureForError ());
9841 var qam = this as QualifiedAliasMember;
9843 rc.Module.Compiler.Report.Error (431, loc,
9844 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9849 TypeSpec nested = null;
9850 while (expr_type != null) {
9851 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9852 if (nested == null) {
9853 if (expr_type == tnew_expr) {
9854 Error_IdentifierNotFound (rc, expr_type);
9858 expr_type = tnew_expr;
9859 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9860 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9864 if (nested.IsAccessible (rc))
9868 // Keep looking after inaccessible candidate but only if
9869 // we are not in same context as the definition itself
9871 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9874 expr_type = expr_type.BaseType;
9879 if (HasTypeArguments) {
9880 texpr = new GenericTypeExpr (nested, targs, loc);
9882 if (!allowUnboundTypeArguments || expr_resolved is GenericTypeExpr) // && HasTypeArguments
9883 Error_OpenGenericTypeIsNotAllowed (rc);
9885 texpr = new GenericOpenTypeExpr (nested, loc);
9887 } else if (expr_resolved is GenericOpenTypeExpr) {
9888 texpr = new GenericOpenTypeExpr (nested, loc);
9890 texpr = new TypeExpression (nested, loc);
9893 if (texpr.ResolveAsType (rc) == null)
9899 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9901 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9903 if (nested != null) {
9904 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9908 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9909 if (any_other_member != null) {
9910 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9914 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9915 Name, expr_type.GetSignatureForError ());
9918 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9920 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9923 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9925 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9926 ec.Report.SymbolRelatedToPreviousError (type);
9928 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9930 // a using directive or an assembly reference
9932 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9934 missing = "an assembly reference";
9937 ec.Report.Error (1061, loc,
9938 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9939 type.GetSignatureForError (), name, missing);
9943 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9946 public override string GetSignatureForError ()
9948 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9951 protected override void CloneTo (CloneContext clonectx, Expression t)
9953 MemberAccess target = (MemberAccess) t;
9955 target.expr = expr.Clone (clonectx);
9958 public override object Accept (StructuralVisitor visitor)
9960 return visitor.Visit (this);
9964 public class ConditionalMemberAccess : MemberAccess
9966 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9967 : base (expr, identifier, args, loc)
9971 public override bool HasConditionalAccess ()
9978 /// Implements checked expressions
9980 public class CheckedExpr : Expression {
9982 public Expression Expr;
9984 public CheckedExpr (Expression e, Location l)
9990 public override bool ContainsEmitWithAwait ()
9992 return Expr.ContainsEmitWithAwait ();
9995 public override Expression CreateExpressionTree (ResolveContext ec)
9997 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9998 return Expr.CreateExpressionTree (ec);
10001 protected override Expression DoResolve (ResolveContext ec)
10003 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10004 Expr = Expr.Resolve (ec);
10009 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10012 eclass = Expr.eclass;
10017 public override void Emit (EmitContext ec)
10019 using (ec.With (EmitContext.Options.CheckedScope, true))
10023 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10025 using (ec.With (EmitContext.Options.CheckedScope, true))
10026 Expr.EmitBranchable (ec, target, on_true);
10029 public override void FlowAnalysis (FlowAnalysisContext fc)
10031 Expr.FlowAnalysis (fc);
10034 public override SLE.Expression MakeExpression (BuilderContext ctx)
10036 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10037 return Expr.MakeExpression (ctx);
10041 protected override void CloneTo (CloneContext clonectx, Expression t)
10043 CheckedExpr target = (CheckedExpr) t;
10045 target.Expr = Expr.Clone (clonectx);
10048 public override object Accept (StructuralVisitor visitor)
10050 return visitor.Visit (this);
10055 /// Implements the unchecked expression
10057 public class UnCheckedExpr : Expression {
10059 public Expression Expr;
10061 public UnCheckedExpr (Expression e, Location l)
10067 public override bool ContainsEmitWithAwait ()
10069 return Expr.ContainsEmitWithAwait ();
10072 public override Expression CreateExpressionTree (ResolveContext ec)
10074 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10075 return Expr.CreateExpressionTree (ec);
10078 protected override Expression DoResolve (ResolveContext ec)
10080 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10081 Expr = Expr.Resolve (ec);
10086 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10089 eclass = Expr.eclass;
10094 public override void Emit (EmitContext ec)
10096 using (ec.With (EmitContext.Options.CheckedScope, false))
10100 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10102 using (ec.With (EmitContext.Options.CheckedScope, false))
10103 Expr.EmitBranchable (ec, target, on_true);
10106 public override void FlowAnalysis (FlowAnalysisContext fc)
10108 Expr.FlowAnalysis (fc);
10111 protected override void CloneTo (CloneContext clonectx, Expression t)
10113 UnCheckedExpr target = (UnCheckedExpr) t;
10115 target.Expr = Expr.Clone (clonectx);
10118 public override object Accept (StructuralVisitor visitor)
10120 return visitor.Visit (this);
10125 /// An Element Access expression.
10127 /// During semantic analysis these are transformed into
10128 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10130 public class ElementAccess : Expression
10132 public Arguments Arguments;
10133 public Expression Expr;
10135 public ElementAccess (Expression e, Arguments args, Location loc)
10139 this.Arguments = args;
10142 public bool ConditionalAccess { get; set; }
10144 public override Location StartLocation {
10146 return Expr.StartLocation;
10150 public override bool ContainsEmitWithAwait ()
10152 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10156 // We perform some simple tests, and then to "split" the emit and store
10157 // code we create an instance of a different class, and return that.
10159 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10161 Expr = Expr.Resolve (ec);
10167 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10168 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10173 return new ArrayAccess (this, loc) {
10174 ConditionalAccess = ConditionalAccess,
10175 ConditionalAccessReceiver = conditionalAccessReceiver
10178 if (type.IsPointer)
10179 return MakePointerAccess (ec, type);
10181 FieldExpr fe = Expr as FieldExpr;
10183 var ff = fe.Spec as FixedFieldSpec;
10185 return MakePointerAccess (ec, ff.ElementType);
10189 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10190 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10191 var indexer = new IndexerExpr (indexers, type, this) {
10192 ConditionalAccess = ConditionalAccess
10195 if (conditionalAccessReceiver)
10196 indexer.SetConditionalAccessReceiver ();
10201 Error_CannotApplyIndexing (ec, type, loc);
10206 public override Expression CreateExpressionTree (ResolveContext ec)
10208 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10209 Expr.CreateExpressionTree (ec));
10211 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10214 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10216 if (type != InternalType.ErrorType) {
10217 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10218 type.GetSignatureForError ());
10222 public override bool HasConditionalAccess ()
10224 return ConditionalAccess || Expr.HasConditionalAccess ();
10227 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
10229 if (Arguments.Count != 1){
10230 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
10234 var arg = Arguments[0];
10235 if (arg is NamedArgument)
10236 Error_NamedArgument ((NamedArgument) arg, rc.Report);
10238 var index = arg.Expr.Resolve (rc);
10242 index = ConvertExpressionToArrayIndex (rc, index, true);
10244 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
10245 return new Indirection (p, loc);
10248 protected override Expression DoResolve (ResolveContext rc)
10251 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10252 if (HasConditionalAccess ()) {
10253 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10254 expr = CreateAccessExpression (rc, true);
10258 return expr.Resolve (rc);
10263 expr = CreateAccessExpression (rc, false);
10267 return expr.Resolve (rc);
10270 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10272 var res = CreateAccessExpression (ec, false);
10276 return res.ResolveLValue (ec, rhs);
10279 public override void Emit (EmitContext ec)
10281 throw new Exception ("Should never be reached");
10284 public static void Error_NamedArgument (NamedArgument na, Report Report)
10286 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
10289 public override void FlowAnalysis (FlowAnalysisContext fc)
10291 Expr.FlowAnalysis (fc);
10293 if (ConditionalAccess)
10294 fc.BranchConditionalAccessDefiniteAssignment ();
10296 Arguments.FlowAnalysis (fc);
10299 public override string GetSignatureForError ()
10301 return Expr.GetSignatureForError ();
10304 protected override void CloneTo (CloneContext clonectx, Expression t)
10306 ElementAccess target = (ElementAccess) t;
10308 target.Expr = Expr.Clone (clonectx);
10309 if (Arguments != null)
10310 target.Arguments = Arguments.Clone (clonectx);
10313 public override object Accept (StructuralVisitor visitor)
10315 return visitor.Visit (this);
10320 /// Implements array access
10322 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10324 // Points to our "data" repository
10328 LocalTemporary temp;
10330 bool? has_await_args;
10332 public ArrayAccess (ElementAccess ea_data, Location l)
10338 public bool ConditionalAccess { get; set; }
10340 public bool ConditionalAccessReceiver { get; set; }
10342 public void AddressOf (EmitContext ec, AddressOp mode)
10344 var ac = (ArrayContainer) ea.Expr.Type;
10346 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10347 LoadInstanceAndArguments (ec, false, true);
10350 LoadInstanceAndArguments (ec, false, false);
10352 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10353 ec.Emit (OpCodes.Readonly);
10355 ec.EmitArrayAddress (ac);
10358 public override Expression CreateExpressionTree (ResolveContext ec)
10360 if (ConditionalAccess)
10361 Error_NullShortCircuitInsideExpressionTree (ec);
10363 return ea.CreateExpressionTree (ec);
10366 public override bool ContainsEmitWithAwait ()
10368 return ea.ContainsEmitWithAwait ();
10371 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10373 if (ConditionalAccess)
10374 throw new NotSupportedException ("null propagating operator assignment");
10376 return DoResolve (ec);
10379 protected override Expression DoResolve (ResolveContext ec)
10381 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10383 ea.Arguments.Resolve (ec, out dynamic);
10385 var ac = ea.Expr.Type as ArrayContainer;
10386 int rank = ea.Arguments.Count;
10387 if (ac.Rank != rank) {
10388 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10389 rank.ToString (), ac.Rank.ToString ());
10394 if (type.IsPointer && !ec.IsUnsafe) {
10395 UnsafeError (ec, ea.Location);
10398 if (ConditionalAccessReceiver)
10399 type = LiftMemberType (ec, type);
10401 foreach (Argument a in ea.Arguments) {
10402 var na = a as NamedArgument;
10404 ElementAccess.Error_NamedArgument (na, ec.Report);
10406 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10409 eclass = ExprClass.Variable;
10414 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10416 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10419 public override void FlowAnalysis (FlowAnalysisContext fc)
10421 ea.FlowAnalysis (fc);
10425 // Load the array arguments into the stack.
10427 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10429 if (prepareAwait) {
10430 ea.Expr = ea.Expr.EmitToField (ec);
10432 var ie = new InstanceEmitter (ea.Expr, false);
10433 ie.Emit (ec, ConditionalAccess);
10435 if (duplicateArguments) {
10436 ec.Emit (OpCodes.Dup);
10438 var copy = new LocalTemporary (ea.Expr.Type);
10444 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10445 if (dup_args != null)
10446 ea.Arguments = dup_args;
10449 public void Emit (EmitContext ec, bool leave_copy)
10452 ec.EmitLoadFromPtr (type);
10454 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10455 LoadInstanceAndArguments (ec, false, true);
10458 if (ConditionalAccessReceiver)
10459 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10461 var ac = (ArrayContainer) ea.Expr.Type;
10462 LoadInstanceAndArguments (ec, false, false);
10463 ec.EmitArrayLoad (ac);
10465 if (ConditionalAccessReceiver)
10466 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10470 ec.Emit (OpCodes.Dup);
10471 temp = new LocalTemporary (this.type);
10476 public override void Emit (EmitContext ec)
10481 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10483 var ac = (ArrayContainer) ea.Expr.Type;
10484 TypeSpec t = source.Type;
10486 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10489 // When we are dealing with a struct, get the address of it to avoid value copy
10490 // Same cannot be done for reference type because array covariance and the
10491 // check in ldelema requires to specify the type of array element stored at the index
10493 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10494 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10496 if (has_await_args.Value) {
10497 if (source.ContainsEmitWithAwait ()) {
10498 source = source.EmitToField (ec);
10499 isCompound = false;
10503 LoadInstanceAndArguments (ec, isCompound, false);
10508 ec.EmitArrayAddress (ac);
10511 ec.Emit (OpCodes.Dup);
10515 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10517 if (has_await_args.Value) {
10518 if (source.ContainsEmitWithAwait ())
10519 source = source.EmitToField (ec);
10521 LoadInstanceAndArguments (ec, false, false);
10528 var lt = ea.Expr as LocalTemporary;
10534 ec.Emit (OpCodes.Dup);
10535 temp = new LocalTemporary (this.type);
10540 ec.EmitStoreFromPtr (t);
10542 ec.EmitArrayStore (ac);
10545 if (temp != null) {
10551 public override Expression EmitToField (EmitContext ec)
10554 // Have to be specialized for arrays to get access to
10555 // underlying element. Instead of another result copy we
10556 // need direct access to element
10560 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10562 ea.Expr = ea.Expr.EmitToField (ec);
10563 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10567 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10569 #if NET_4_0 || MOBILE_DYNAMIC
10570 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10572 throw new NotImplementedException ();
10576 public override SLE.Expression MakeExpression (BuilderContext ctx)
10578 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10581 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10583 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10584 return Arguments.MakeExpression (ea.Arguments, ctx);
10590 // Indexer access expression
10592 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10594 IList<MemberSpec> indexers;
10595 Arguments arguments;
10596 TypeSpec queried_type;
10598 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10599 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10603 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10606 this.indexers = indexers;
10607 this.queried_type = queriedType;
10608 this.InstanceExpression = instance;
10609 this.arguments = args;
10614 protected override Arguments Arguments {
10623 protected override TypeSpec DeclaringType {
10625 return best_candidate.DeclaringType;
10629 public override bool IsInstance {
10635 public override bool IsStatic {
10641 public override string KindName {
10642 get { return "indexer"; }
10645 public override string Name {
10653 public override bool ContainsEmitWithAwait ()
10655 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10658 public override Expression CreateExpressionTree (ResolveContext ec)
10660 if (ConditionalAccess) {
10661 Error_NullShortCircuitInsideExpressionTree (ec);
10664 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10665 InstanceExpression.CreateExpressionTree (ec),
10666 new TypeOfMethod (Getter, loc));
10668 return CreateExpressionFactoryCall (ec, "Call", args);
10671 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10673 LocalTemporary await_source_arg = null;
10676 emitting_compound_assignment = true;
10677 if (source is DynamicExpressionStatement) {
10682 emitting_compound_assignment = false;
10684 if (has_await_arguments) {
10685 await_source_arg = new LocalTemporary (Type);
10686 await_source_arg.Store (ec);
10688 arguments.Add (new Argument (await_source_arg));
10691 temp = await_source_arg;
10694 has_await_arguments = false;
10699 ec.Emit (OpCodes.Dup);
10700 temp = new LocalTemporary (Type);
10706 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10707 source = source.EmitToField (ec);
10709 temp = new LocalTemporary (Type);
10716 arguments.Add (new Argument (source));
10719 var call = new CallEmitter ();
10720 call.InstanceExpression = InstanceExpression;
10721 if (arguments == null)
10722 call.InstanceExpressionOnStack = true;
10724 call.Emit (ec, Setter, arguments, loc);
10726 if (temp != null) {
10729 } else if (leave_copy) {
10733 if (await_source_arg != null) {
10734 await_source_arg.Release (ec);
10738 public override void FlowAnalysis (FlowAnalysisContext fc)
10740 base.FlowAnalysis (fc);
10741 arguments.FlowAnalysis (fc);
10743 if (conditional_access_receiver)
10744 fc.ConditionalAccessEnd ();
10747 public override string GetSignatureForError ()
10749 return best_candidate.GetSignatureForError ();
10752 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10755 throw new NotSupportedException ();
10757 var value = new[] { source.MakeExpression (ctx) };
10758 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10759 #if NET_4_0 || MOBILE_DYNAMIC
10760 return SLE.Expression.Block (
10761 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10764 return args.First ();
10769 public override SLE.Expression MakeExpression (BuilderContext ctx)
10772 return base.MakeExpression (ctx);
10774 var args = Arguments.MakeExpression (arguments, ctx);
10775 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10779 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10781 if (best_candidate != null)
10784 eclass = ExprClass.IndexerAccess;
10787 arguments.Resolve (rc, out dynamic);
10789 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10792 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10793 res.BaseMembersProvider = this;
10794 res.InstanceQualifier = this;
10796 // TODO: Do I need 2 argument sets?
10797 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10798 if (best_candidate != null)
10799 type = res.BestCandidateReturnType;
10800 else if (!res.BestCandidateIsDynamic)
10805 // It has dynamic arguments
10808 Arguments args = new Arguments (arguments.Count + 1);
10810 rc.Report.Error (1972, loc,
10811 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10813 args.Add (new Argument (InstanceExpression));
10815 args.AddRange (arguments);
10817 best_candidate = null;
10818 return new DynamicIndexBinder (args, loc);
10822 // Try to avoid resolving left expression again
10824 if (right_side != null)
10825 ResolveInstanceExpression (rc, right_side);
10830 protected override void CloneTo (CloneContext clonectx, Expression t)
10832 IndexerExpr target = (IndexerExpr) t;
10834 if (arguments != null)
10835 target.arguments = arguments.Clone (clonectx);
10838 public void SetConditionalAccessReceiver ()
10840 conditional_access_receiver = true;
10843 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10845 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10848 #region IBaseMembersProvider Members
10850 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10852 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10855 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10857 if (queried_type == member.DeclaringType)
10860 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10861 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10864 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10873 // A base access expression
10875 public class BaseThis : This
10877 public BaseThis (Location loc)
10882 public BaseThis (TypeSpec type, Location loc)
10886 eclass = ExprClass.Variable;
10891 public override string Name {
10899 public override Expression CreateExpressionTree (ResolveContext ec)
10901 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10902 return base.CreateExpressionTree (ec);
10905 public override void Emit (EmitContext ec)
10909 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10910 var context_type = ec.CurrentType;
10911 ec.Emit (OpCodes.Ldobj, context_type);
10912 ec.Emit (OpCodes.Box, context_type);
10916 protected override void Error_ThisNotAvailable (ResolveContext ec)
10919 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10921 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10925 public override void ResolveBase (ResolveContext ec)
10927 base.ResolveBase (ec);
10928 type = ec.CurrentType.BaseType;
10931 public override object Accept (StructuralVisitor visitor)
10933 return visitor.Visit (this);
10938 /// This class exists solely to pass the Type around and to be a dummy
10939 /// that can be passed to the conversion functions (this is used by
10940 /// foreach implementation to typecast the object return value from
10941 /// get_Current into the proper type. All code has been generated and
10942 /// we only care about the side effect conversions to be performed
10944 /// This is also now used as a placeholder where a no-action expression
10945 /// is needed (the `New' class).
10947 public class EmptyExpression : Expression
10949 sealed class OutAccessExpression : EmptyExpression
10951 public OutAccessExpression (TypeSpec t)
10956 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10958 rc.Report.Error (206, right_side.Location,
10959 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10965 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10966 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10967 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10968 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10969 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10970 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10971 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10972 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10974 public EmptyExpression (TypeSpec t)
10977 eclass = ExprClass.Value;
10978 loc = Location.Null;
10981 protected override void CloneTo (CloneContext clonectx, Expression target)
10985 public override bool ContainsEmitWithAwait ()
10990 public override Expression CreateExpressionTree (ResolveContext ec)
10992 throw new NotSupportedException ("ET");
10995 protected override Expression DoResolve (ResolveContext ec)
11000 public override void Emit (EmitContext ec)
11002 // nothing, as we only exist to not do anything.
11005 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11009 public override void EmitSideEffect (EmitContext ec)
11013 public override object Accept (StructuralVisitor visitor)
11015 return visitor.Visit (this);
11019 sealed class EmptyAwaitExpression : EmptyExpression
11021 public EmptyAwaitExpression (TypeSpec type)
11026 public override bool ContainsEmitWithAwait ()
11033 // Empty statement expression
11035 public sealed class EmptyExpressionStatement : ExpressionStatement
11037 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11039 private EmptyExpressionStatement ()
11041 loc = Location.Null;
11044 public override bool ContainsEmitWithAwait ()
11049 public override Expression CreateExpressionTree (ResolveContext ec)
11054 public override void EmitStatement (EmitContext ec)
11059 protected override Expression DoResolve (ResolveContext ec)
11061 eclass = ExprClass.Value;
11062 type = ec.BuiltinTypes.Object;
11066 public override void Emit (EmitContext ec)
11071 public override object Accept (StructuralVisitor visitor)
11073 return visitor.Visit (this);
11077 public class ErrorExpression : EmptyExpression
11079 public static readonly ErrorExpression Instance = new ErrorExpression ();
11081 private ErrorExpression ()
11082 : base (InternalType.ErrorType)
11086 public override Expression CreateExpressionTree (ResolveContext ec)
11091 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11096 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11100 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11104 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11108 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11112 public override object Accept (StructuralVisitor visitor)
11114 return visitor.Visit (this);
11118 public class UserCast : Expression {
11122 public UserCast (MethodSpec method, Expression source, Location l)
11124 if (source == null)
11125 throw new ArgumentNullException ("source");
11127 this.method = method;
11128 this.source = source;
11129 type = method.ReturnType;
11133 public Expression Source {
11139 public override bool ContainsEmitWithAwait ()
11141 return source.ContainsEmitWithAwait ();
11144 public override Expression CreateExpressionTree (ResolveContext ec)
11146 Arguments args = new Arguments (3);
11147 args.Add (new Argument (source.CreateExpressionTree (ec)));
11148 args.Add (new Argument (new TypeOf (type, loc)));
11149 args.Add (new Argument (new TypeOfMethod (method, loc)));
11150 return CreateExpressionFactoryCall (ec, "Convert", args);
11153 protected override Expression DoResolve (ResolveContext ec)
11155 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11157 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11159 eclass = ExprClass.Value;
11163 public override void Emit (EmitContext ec)
11166 ec.MarkCallEntry (loc);
11167 ec.Emit (OpCodes.Call, method);
11170 public override void FlowAnalysis (FlowAnalysisContext fc)
11172 source.FlowAnalysis (fc);
11175 public override string GetSignatureForError ()
11177 return TypeManager.CSharpSignature (method);
11180 public override SLE.Expression MakeExpression (BuilderContext ctx)
11183 return base.MakeExpression (ctx);
11185 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11191 // Holds additional type specifiers like ?, *, []
11193 public class ComposedTypeSpecifier
11195 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11197 public readonly int Dimension;
11198 public readonly Location Location;
11200 public ComposedTypeSpecifier (int specifier, Location loc)
11202 this.Dimension = specifier;
11203 this.Location = loc;
11207 public bool IsNullable {
11209 return Dimension == -1;
11213 public bool IsPointer {
11215 return Dimension == -2;
11219 public ComposedTypeSpecifier Next { get; set; }
11223 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11225 return new ComposedTypeSpecifier (dimension, loc);
11228 public static ComposedTypeSpecifier CreateNullable (Location loc)
11230 return new ComposedTypeSpecifier (-1, loc);
11233 public static ComposedTypeSpecifier CreatePointer (Location loc)
11235 return new ComposedTypeSpecifier (-2, loc);
11238 public string GetSignatureForError ()
11243 ArrayContainer.GetPostfixSignature (Dimension);
11245 return Next != null ? s + Next.GetSignatureForError () : s;
11250 // This class is used to "construct" the type during a typecast
11251 // operation. Since the Type.GetType class in .NET can parse
11252 // the type specification, we just use this to construct the type
11253 // one bit at a time.
11255 public class ComposedCast : TypeExpr {
11256 FullNamedExpression left;
11257 ComposedTypeSpecifier spec;
11259 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11262 throw new ArgumentNullException ("spec");
11266 this.loc = left.Location;
11269 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11271 type = left.ResolveAsType (ec);
11275 eclass = ExprClass.Type;
11277 var single_spec = spec;
11279 if (single_spec.IsNullable) {
11280 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11284 single_spec = single_spec.Next;
11285 } else if (single_spec.IsPointer) {
11286 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11289 if (!ec.IsUnsafe) {
11290 UnsafeError (ec.Module.Compiler.Report, loc);
11294 type = PointerContainer.MakeType (ec.Module, type);
11295 single_spec = single_spec.Next;
11296 } while (single_spec != null && single_spec.IsPointer);
11299 if (single_spec != null && single_spec.Dimension > 0) {
11300 if (type.IsSpecialRuntimeType) {
11301 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11302 } else if (type.IsStatic) {
11303 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11304 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11305 type.GetSignatureForError ());
11307 MakeArray (ec.Module, single_spec);
11314 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11316 if (spec.Next != null)
11317 MakeArray (module, spec.Next);
11319 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11322 public override string GetSignatureForError ()
11324 return left.GetSignatureForError () + spec.GetSignatureForError ();
11327 public override object Accept (StructuralVisitor visitor)
11329 return visitor.Visit (this);
11333 class FixedBufferPtr : Expression
11335 readonly Expression array;
11337 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11339 this.type = array_type;
11340 this.array = array;
11344 public override bool ContainsEmitWithAwait ()
11346 throw new NotImplementedException ();
11349 public override Expression CreateExpressionTree (ResolveContext ec)
11351 Error_PointerInsideExpressionTree (ec);
11355 public override void Emit(EmitContext ec)
11360 protected override Expression DoResolve (ResolveContext ec)
11362 type = PointerContainer.MakeType (ec.Module, type);
11363 eclass = ExprClass.Value;
11370 // This class is used to represent the address of an array, used
11371 // only by the Fixed statement, this generates "&a [0]" construct
11372 // for fixed (char *pa = a)
11374 class ArrayPtr : FixedBufferPtr
11376 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11377 base (array, array_type, l)
11381 public override void Emit (EmitContext ec)
11386 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11391 // Encapsulates a conversion rules required for array indexes
11393 public class ArrayIndexCast : TypeCast
11395 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11396 : base (expr, returnType)
11398 if (expr.Type == returnType) // int -> int
11399 throw new ArgumentException ("unnecessary array index conversion");
11402 public override Expression CreateExpressionTree (ResolveContext ec)
11404 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11405 return base.CreateExpressionTree (ec);
11409 public override void Emit (EmitContext ec)
11413 switch (child.Type.BuiltinType) {
11414 case BuiltinTypeSpec.Type.UInt:
11415 ec.Emit (OpCodes.Conv_U);
11417 case BuiltinTypeSpec.Type.Long:
11418 ec.Emit (OpCodes.Conv_Ovf_I);
11420 case BuiltinTypeSpec.Type.ULong:
11421 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11424 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11430 // Implements the `stackalloc' keyword
11432 public class StackAlloc : Expression {
11437 public StackAlloc (Expression type, Expression count, Location l)
11440 this.count = count;
11444 public Expression TypeExpression {
11450 public Expression CountExpression {
11456 public override bool ContainsEmitWithAwait ()
11461 public override Expression CreateExpressionTree (ResolveContext ec)
11463 throw new NotSupportedException ("ET");
11466 protected override Expression DoResolve (ResolveContext ec)
11468 count = count.Resolve (ec);
11472 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11473 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11478 Constant c = count as Constant;
11479 if (c != null && c.IsNegative) {
11480 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11483 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11484 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11487 otype = t.ResolveAsType (ec);
11491 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11494 type = PointerContainer.MakeType (ec.Module, otype);
11495 eclass = ExprClass.Value;
11500 public override void Emit (EmitContext ec)
11502 int size = BuiltinTypeSpec.GetSize (otype);
11507 ec.Emit (OpCodes.Sizeof, otype);
11511 ec.Emit (OpCodes.Mul_Ovf_Un);
11512 ec.Emit (OpCodes.Localloc);
11515 protected override void CloneTo (CloneContext clonectx, Expression t)
11517 StackAlloc target = (StackAlloc) t;
11518 target.count = count.Clone (clonectx);
11519 target.t = t.Clone (clonectx);
11522 public override object Accept (StructuralVisitor visitor)
11524 return visitor.Visit (this);
11529 // An object initializer expression
11531 public class ElementInitializer : Assign
11533 public readonly string Name;
11535 public ElementInitializer (string name, Expression initializer, Location loc)
11536 : base (null, initializer, loc)
11541 public bool IsDictionaryInitializer {
11543 return Name == null;
11547 protected override void CloneTo (CloneContext clonectx, Expression t)
11549 ElementInitializer target = (ElementInitializer) t;
11550 target.source = source.Clone (clonectx);
11553 public override Expression CreateExpressionTree (ResolveContext ec)
11555 Arguments args = new Arguments (2);
11556 FieldExpr fe = target as FieldExpr;
11558 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11560 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11563 Expression arg_expr;
11564 var cinit = source as CollectionOrObjectInitializers;
11565 if (cinit == null) {
11567 arg_expr = source.CreateExpressionTree (ec);
11569 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11570 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11573 args.Add (new Argument (arg_expr));
11574 return CreateExpressionFactoryCall (ec, mname, args);
11577 protected override Expression DoResolve (ResolveContext ec)
11579 if (source == null)
11580 return EmptyExpressionStatement.Instance;
11582 if (!ResolveElement (ec))
11585 if (source is CollectionOrObjectInitializers) {
11586 Expression previous = ec.CurrentInitializerVariable;
11587 ec.CurrentInitializerVariable = target;
11588 source = source.Resolve (ec);
11589 ec.CurrentInitializerVariable = previous;
11590 if (source == null)
11593 eclass = source.eclass;
11594 type = source.Type;
11598 return base.DoResolve (ec);
11601 public override void EmitStatement (EmitContext ec)
11603 if (source is CollectionOrObjectInitializers)
11606 base.EmitStatement (ec);
11609 protected virtual bool ResolveElement (ResolveContext rc)
11611 var t = rc.CurrentInitializerVariable.Type;
11612 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11613 Arguments args = new Arguments (1);
11614 args.Add (new Argument (rc.CurrentInitializerVariable));
11615 target = new DynamicMemberBinder (Name, args, loc);
11618 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11619 if (member == null) {
11620 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11622 if (member != null) {
11623 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11624 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11629 if (member == null) {
11630 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11634 var me = member as MemberExpr;
11635 if (me is EventExpr) {
11636 me = me.ResolveMemberAccess (rc, null, null);
11637 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11638 rc.Report.Error (1913, loc,
11639 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11640 member.GetSignatureForError ());
11646 rc.Report.Error (1914, loc,
11647 "Static field or property `{0}' cannot be assigned in an object initializer",
11648 me.GetSignatureForError ());
11652 me.InstanceExpression = rc.CurrentInitializerVariable;
11660 // A collection initializer expression
11662 class CollectionElementInitializer : Invocation
11664 public class ElementInitializerArgument : Argument
11666 public ElementInitializerArgument (Expression e)
11672 sealed class AddMemberAccess : MemberAccess
11674 public AddMemberAccess (Expression expr, Location loc)
11675 : base (expr, "Add", loc)
11679 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11681 if (TypeManager.HasElementType (type))
11684 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11688 public CollectionElementInitializer (Expression argument)
11689 : base (null, new Arguments (1))
11691 base.arguments.Add (new ElementInitializerArgument (argument));
11692 this.loc = argument.Location;
11695 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11696 : base (null, new Arguments (arguments.Count))
11698 foreach (Expression e in arguments)
11699 base.arguments.Add (new ElementInitializerArgument (e));
11704 public CollectionElementInitializer (Location loc)
11705 : base (null, null)
11710 public override Expression CreateExpressionTree (ResolveContext ec)
11712 Arguments args = new Arguments (2);
11713 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11715 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11716 foreach (Argument a in arguments)
11717 expr_initializers.Add (a.CreateExpressionTree (ec));
11719 args.Add (new Argument (new ArrayCreation (
11720 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11721 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11724 protected override void CloneTo (CloneContext clonectx, Expression t)
11726 CollectionElementInitializer target = (CollectionElementInitializer) t;
11727 if (arguments != null)
11728 target.arguments = arguments.Clone (clonectx);
11731 protected override Expression DoResolve (ResolveContext ec)
11733 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11735 return base.DoResolve (ec);
11739 class DictionaryElementInitializer : ElementInitializer
11741 readonly Arguments args;
11743 public DictionaryElementInitializer (List<Expression> arguments, Expression initializer, Location loc)
11744 : base (null, initializer, loc)
11746 this.args = new Arguments (arguments.Count);
11747 foreach (var arg in arguments)
11748 this.args.Add (new Argument (arg));
11751 public override Expression CreateExpressionTree (ResolveContext ec)
11753 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11757 protected override bool ResolveElement (ResolveContext rc)
11759 var init = rc.CurrentInitializerVariable;
11760 var type = init.Type;
11762 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11763 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11764 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11768 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11774 // A block of object or collection initializers
11776 public class CollectionOrObjectInitializers : ExpressionStatement
11778 IList<Expression> initializers;
11779 bool is_collection_initialization;
11781 public CollectionOrObjectInitializers (Location loc)
11782 : this (new Expression[0], loc)
11786 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11788 this.initializers = initializers;
11792 public IList<Expression> Initializers {
11794 return initializers;
11798 public bool IsEmpty {
11800 return initializers.Count == 0;
11804 public bool IsCollectionInitializer {
11806 return is_collection_initialization;
11810 protected override void CloneTo (CloneContext clonectx, Expression target)
11812 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11814 t.initializers = new List<Expression> (initializers.Count);
11815 foreach (var e in initializers)
11816 t.initializers.Add (e.Clone (clonectx));
11819 public override bool ContainsEmitWithAwait ()
11821 foreach (var e in initializers) {
11822 if (e.ContainsEmitWithAwait ())
11829 public override Expression CreateExpressionTree (ResolveContext ec)
11831 return CreateExpressionTree (ec, false);
11834 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11836 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11837 foreach (Expression e in initializers) {
11838 Expression expr = e.CreateExpressionTree (ec);
11840 expr_initializers.Add (expr);
11844 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11846 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11849 protected override Expression DoResolve (ResolveContext ec)
11851 List<string> element_names = null;
11852 for (int i = 0; i < initializers.Count; ++i) {
11853 Expression initializer = initializers [i];
11854 ElementInitializer element_initializer = initializer as ElementInitializer;
11857 if (element_initializer != null) {
11858 element_names = new List<string> (initializers.Count);
11859 if (!element_initializer.IsDictionaryInitializer)
11860 element_names.Add (element_initializer.Name);
11861 } else if (initializer is CompletingExpression) {
11862 initializer.Resolve (ec);
11863 throw new InternalErrorException ("This line should never be reached");
11865 var t = ec.CurrentInitializerVariable.Type;
11866 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11867 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11868 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11869 "object initializer because type `{1}' does not implement `{2}' interface",
11870 ec.CurrentInitializerVariable.GetSignatureForError (),
11871 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11872 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11875 is_collection_initialization = true;
11878 if (is_collection_initialization != (element_initializer == null)) {
11879 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11880 is_collection_initialization ? "collection initializer" : "object initializer");
11884 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11885 if (element_names.Contains (element_initializer.Name)) {
11886 ec.Report.Error (1912, element_initializer.Location,
11887 "An object initializer includes more than one member `{0}' initialization",
11888 element_initializer.Name);
11890 element_names.Add (element_initializer.Name);
11895 Expression e = initializer.Resolve (ec);
11896 if (e == EmptyExpressionStatement.Instance)
11897 initializers.RemoveAt (i--);
11899 initializers [i] = e;
11902 type = ec.CurrentInitializerVariable.Type;
11903 if (is_collection_initialization) {
11904 if (TypeManager.HasElementType (type)) {
11905 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11906 type.GetSignatureForError ());
11910 eclass = ExprClass.Variable;
11914 public override void Emit (EmitContext ec)
11916 EmitStatement (ec);
11919 public override void EmitStatement (EmitContext ec)
11921 foreach (ExpressionStatement e in initializers) {
11922 // TODO: need location region
11923 ec.Mark (e.Location);
11924 e.EmitStatement (ec);
11928 public override void FlowAnalysis (FlowAnalysisContext fc)
11930 foreach (var initializer in initializers) {
11931 if (initializer != null)
11932 initializer.FlowAnalysis (fc);
11938 // New expression with element/object initializers
11940 public class NewInitialize : New
11943 // This class serves as a proxy for variable initializer target instances.
11944 // A real variable is assigned later when we resolve left side of an
11947 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11949 NewInitialize new_instance;
11951 public InitializerTargetExpression (NewInitialize newInstance)
11953 this.type = newInstance.type;
11954 this.loc = newInstance.loc;
11955 this.eclass = newInstance.eclass;
11956 this.new_instance = newInstance;
11959 public override bool ContainsEmitWithAwait ()
11964 public override Expression CreateExpressionTree (ResolveContext ec)
11966 // Should not be reached
11967 throw new NotSupportedException ("ET");
11970 protected override Expression DoResolve (ResolveContext ec)
11975 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
11980 public override void Emit (EmitContext ec)
11982 Expression e = (Expression) new_instance.instance;
11986 public override Expression EmitToField (EmitContext ec)
11988 return (Expression) new_instance.instance;
11991 #region IMemoryLocation Members
11993 public void AddressOf (EmitContext ec, AddressOp mode)
11995 new_instance.instance.AddressOf (ec, mode);
12001 CollectionOrObjectInitializers initializers;
12002 IMemoryLocation instance;
12003 DynamicExpressionStatement dynamic;
12005 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12006 : base (requested_type, arguments, l)
12008 this.initializers = initializers;
12011 public CollectionOrObjectInitializers Initializers {
12013 return initializers;
12017 protected override void CloneTo (CloneContext clonectx, Expression t)
12019 base.CloneTo (clonectx, t);
12021 NewInitialize target = (NewInitialize) t;
12022 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12025 public override bool ContainsEmitWithAwait ()
12027 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12030 public override Expression CreateExpressionTree (ResolveContext ec)
12032 Arguments args = new Arguments (2);
12033 args.Add (new Argument (base.CreateExpressionTree (ec)));
12034 if (!initializers.IsEmpty)
12035 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12037 return CreateExpressionFactoryCall (ec,
12038 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12042 protected override Expression DoResolve (ResolveContext ec)
12044 Expression e = base.DoResolve (ec);
12048 if (type.IsDelegate) {
12049 ec.Report.Error (1958, Initializers.Location,
12050 "Object and collection initializers cannot be used to instantiate a delegate");
12053 Expression previous = ec.CurrentInitializerVariable;
12054 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12055 initializers.Resolve (ec);
12056 ec.CurrentInitializerVariable = previous;
12058 dynamic = e as DynamicExpressionStatement;
12059 if (dynamic != null)
12065 public override void Emit (EmitContext ec)
12067 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12068 var fe = ec.GetTemporaryField (type);
12070 if (!Emit (ec, fe))
12079 public override bool Emit (EmitContext ec, IMemoryLocation target)
12081 bool left_on_stack;
12082 if (dynamic != null) {
12084 left_on_stack = true;
12086 left_on_stack = base.Emit (ec, target);
12089 if (initializers.IsEmpty)
12090 return left_on_stack;
12092 LocalTemporary temp = null;
12094 instance = target as LocalTemporary;
12095 if (instance == null)
12096 instance = target as StackFieldExpr;
12098 if (instance == null) {
12099 if (!left_on_stack) {
12100 VariableReference vr = target as VariableReference;
12102 // FIXME: This still does not work correctly for pre-set variables
12103 if (vr != null && vr.IsRef)
12104 target.AddressOf (ec, AddressOp.Load);
12106 ((Expression) target).Emit (ec);
12107 left_on_stack = true;
12110 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12111 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
12113 temp = new LocalTemporary (type);
12118 if (left_on_stack && temp != null)
12121 initializers.Emit (ec);
12123 if (left_on_stack) {
12124 if (temp != null) {
12128 ((Expression) instance).Emit (ec);
12132 return left_on_stack;
12135 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12137 instance = base.EmitAddressOf (ec, Mode);
12139 if (!initializers.IsEmpty)
12140 initializers.Emit (ec);
12145 public override void FlowAnalysis (FlowAnalysisContext fc)
12147 base.FlowAnalysis (fc);
12148 initializers.FlowAnalysis (fc);
12151 public override object Accept (StructuralVisitor visitor)
12153 return visitor.Visit (this);
12157 public class NewAnonymousType : New
12159 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12161 List<AnonymousTypeParameter> parameters;
12162 readonly TypeContainer parent;
12163 AnonymousTypeClass anonymous_type;
12165 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12166 : base (null, null, loc)
12168 this.parameters = parameters;
12169 this.parent = parent;
12172 public List<AnonymousTypeParameter> Parameters {
12174 return this.parameters;
12178 protected override void CloneTo (CloneContext clonectx, Expression target)
12180 if (parameters == null)
12183 NewAnonymousType t = (NewAnonymousType) target;
12184 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12185 foreach (AnonymousTypeParameter atp in parameters)
12186 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12189 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12191 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12195 type = AnonymousTypeClass.Create (parent, parameters, loc);
12199 int errors = ec.Report.Errors;
12200 type.CreateContainer ();
12201 type.DefineContainer ();
12203 if ((ec.Report.Errors - errors) == 0) {
12204 parent.Module.AddAnonymousType (type);
12205 type.PrepareEmit ();
12211 public override Expression CreateExpressionTree (ResolveContext ec)
12213 if (parameters == null)
12214 return base.CreateExpressionTree (ec);
12216 var init = new ArrayInitializer (parameters.Count, loc);
12217 foreach (var m in anonymous_type.Members) {
12218 var p = m as Property;
12220 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12223 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12224 foreach (Argument a in arguments)
12225 ctor_args.Add (a.CreateExpressionTree (ec));
12227 Arguments args = new Arguments (3);
12228 args.Add (new Argument (new TypeOfMethod (method, loc)));
12229 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12230 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12232 return CreateExpressionFactoryCall (ec, "New", args);
12235 protected override Expression DoResolve (ResolveContext ec)
12237 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12238 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12242 if (parameters == null) {
12243 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12244 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12245 return base.DoResolve (ec);
12248 bool error = false;
12249 arguments = new Arguments (parameters.Count);
12250 var t_args = new TypeSpec [parameters.Count];
12251 for (int i = 0; i < parameters.Count; ++i) {
12252 Expression e = parameters [i].Resolve (ec);
12258 arguments.Add (new Argument (e));
12259 t_args [i] = e.Type;
12265 anonymous_type = CreateAnonymousType (ec, parameters);
12266 if (anonymous_type == null)
12269 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12270 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12271 eclass = ExprClass.Value;
12275 public override object Accept (StructuralVisitor visitor)
12277 return visitor.Visit (this);
12281 public class AnonymousTypeParameter : ShimExpression
12283 public readonly string Name;
12285 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12286 : base (initializer)
12292 public AnonymousTypeParameter (Parameter parameter)
12293 : base (new SimpleName (parameter.Name, parameter.Location))
12295 this.Name = parameter.Name;
12296 this.loc = parameter.Location;
12299 public override bool Equals (object o)
12301 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12302 return other != null && Name == other.Name;
12305 public override int GetHashCode ()
12307 return Name.GetHashCode ();
12310 protected override Expression DoResolve (ResolveContext ec)
12312 Expression e = expr.Resolve (ec);
12316 if (e.eclass == ExprClass.MethodGroup) {
12317 Error_InvalidInitializer (ec, e.ExprClassName);
12322 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12323 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12330 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12332 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12333 Name, initializer);
12337 public class CatchFilterExpression : BooleanExpression
12339 public CatchFilterExpression (Expression expr, Location loc)