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.EmitPredefined (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 Expression 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 = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), 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 != null)
587 enum_conversion.Emit (ec);
590 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
592 if (Oper == Operator.LogicalNot)
593 Expr.EmitBranchable (ec, target, !on_true);
595 base.EmitBranchable (ec, target, on_true);
598 public override void EmitSideEffect (EmitContext ec)
600 Expr.EmitSideEffect (ec);
603 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
605 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
606 oper, type.GetSignatureForError ());
609 public override void FlowAnalysis (FlowAnalysisContext fc)
611 if (Oper == Operator.AddressOf) {
612 var vr = Expr as VariableReference;
613 if (vr != null && vr.VariableInfo != null)
614 fc.SetVariableAssigned (vr.VariableInfo);
619 Expr.FlowAnalysis (fc);
621 if (Oper == Operator.LogicalNot) {
622 var temp = fc.DefiniteAssignmentOnTrue;
623 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
624 fc.DefiniteAssignmentOnFalse = temp;
629 // Converts operator to System.Linq.Expressions.ExpressionType enum name
631 string GetOperatorExpressionTypeName ()
634 case Operator.OnesComplement:
635 return "OnesComplement";
636 case Operator.LogicalNot:
638 case Operator.UnaryNegation:
640 case Operator.UnaryPlus:
643 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
647 static bool IsFloat (TypeSpec t)
649 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
653 // Returns a stringified representation of the Operator
655 public static string OperName (Operator oper)
658 case Operator.UnaryPlus:
660 case Operator.UnaryNegation:
662 case Operator.LogicalNot:
664 case Operator.OnesComplement:
666 case Operator.AddressOf:
670 throw new NotImplementedException (oper.ToString ());
673 public override SLE.Expression MakeExpression (BuilderContext ctx)
675 var expr = Expr.MakeExpression (ctx);
676 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
679 case Operator.UnaryNegation:
680 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
681 case Operator.LogicalNot:
682 return SLE.Expression.Not (expr);
683 #if NET_4_0 || MOBILE_DYNAMIC
684 case Operator.OnesComplement:
685 return SLE.Expression.OnesComplement (expr);
688 throw new NotImplementedException (Oper.ToString ());
692 Expression ResolveAddressOf (ResolveContext ec)
695 UnsafeError (ec, loc);
697 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
698 if (Expr == null || Expr.eclass != ExprClass.Variable) {
699 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
703 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
707 IVariableReference vr = Expr as IVariableReference;
710 is_fixed = vr.IsFixed;
711 vr.SetHasAddressTaken ();
714 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
717 IFixedExpression fe = Expr as IFixedExpression;
718 is_fixed = fe != null && fe.IsFixed;
721 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
722 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
725 type = PointerContainer.MakeType (ec.Module, Expr.Type);
726 eclass = ExprClass.Value;
730 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
732 expr = DoNumericPromotion (rc, Oper, expr);
733 TypeSpec expr_type = expr.Type;
734 foreach (TypeSpec t in predefined) {
742 // Perform user-operator overload resolution
744 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
746 CSharp.Operator.OpType op_type;
748 case Operator.LogicalNot:
749 op_type = CSharp.Operator.OpType.LogicalNot; break;
750 case Operator.OnesComplement:
751 op_type = CSharp.Operator.OpType.OnesComplement; break;
752 case Operator.UnaryNegation:
753 op_type = CSharp.Operator.OpType.UnaryNegation; break;
754 case Operator.UnaryPlus:
755 op_type = CSharp.Operator.OpType.UnaryPlus; break;
757 throw new InternalErrorException (Oper.ToString ());
760 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
764 Arguments args = new Arguments (1);
765 args.Add (new Argument (expr));
767 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
768 var oper = res.ResolveOperator (ec, ref args);
773 Expr = args [0].Expr;
774 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
778 // Unary user type overload resolution
780 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
782 Expression best_expr = ResolveUserOperator (ec, expr);
783 if (best_expr != null)
786 foreach (TypeSpec t in predefined) {
787 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
788 if (oper_expr == null)
791 if (oper_expr == ErrorExpression.Instance)
795 // decimal type is predefined but has user-operators
797 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
798 oper_expr = ResolveUserType (ec, oper_expr, predefined);
800 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
802 if (oper_expr == null)
805 if (best_expr == null) {
806 best_expr = oper_expr;
810 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
812 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
813 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
815 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
822 best_expr = oper_expr;
825 if (best_expr == null)
829 // HACK: Decimal user-operator is included in standard operators
831 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
835 type = best_expr.Type;
839 protected override void CloneTo (CloneContext clonectx, Expression t)
841 Unary target = (Unary) t;
843 target.Expr = Expr.Clone (clonectx);
846 public override object Accept (StructuralVisitor visitor)
848 return visitor.Visit (this);
854 // Unary operators are turned into Indirection expressions
855 // after semantic analysis (this is so we can take the address
856 // of an indirection).
858 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
860 LocalTemporary temporary;
863 public Indirection (Expression expr, Location l)
869 public Expression Expr {
875 public bool IsFixed {
879 public override Location StartLocation {
881 return expr.StartLocation;
885 protected override void CloneTo (CloneContext clonectx, Expression t)
887 Indirection target = (Indirection) t;
888 target.expr = expr.Clone (clonectx);
891 public override bool ContainsEmitWithAwait ()
893 throw new NotImplementedException ();
896 public override Expression CreateExpressionTree (ResolveContext ec)
898 Error_PointerInsideExpressionTree (ec);
902 public override void Emit (EmitContext ec)
907 ec.EmitLoadFromPtr (Type);
910 public void Emit (EmitContext ec, bool leave_copy)
914 ec.Emit (OpCodes.Dup);
915 temporary = new LocalTemporary (expr.Type);
916 temporary.Store (ec);
920 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
922 prepared = isCompound;
927 ec.Emit (OpCodes.Dup);
931 ec.Emit (OpCodes.Dup);
932 temporary = new LocalTemporary (source.Type);
933 temporary.Store (ec);
936 ec.EmitStoreFromPtr (type);
938 if (temporary != null) {
940 temporary.Release (ec);
944 public void AddressOf (EmitContext ec, AddressOp Mode)
949 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
951 return DoResolve (ec);
954 protected override Expression DoResolve (ResolveContext ec)
956 expr = expr.Resolve (ec);
961 UnsafeError (ec, loc);
963 var pc = expr.Type as PointerContainer;
966 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
972 if (type.Kind == MemberKind.Void) {
973 Error_VoidPointerOperation (ec);
977 eclass = ExprClass.Variable;
981 public override object Accept (StructuralVisitor visitor)
983 return visitor.Visit (this);
988 /// Unary Mutator expressions (pre and post ++ and --)
992 /// UnaryMutator implements ++ and -- expressions. It derives from
993 /// ExpressionStatement becuase the pre/post increment/decrement
994 /// operators can be used in a statement context.
996 /// FIXME: Idea, we could split this up in two classes, one simpler
997 /// for the common case, and one with the extra fields for more complex
998 /// classes (indexers require temporary access; overloaded require method)
1001 public class UnaryMutator : ExpressionStatement
1003 class DynamicPostMutator : Expression, IAssignMethod
1005 LocalTemporary temp;
1008 public DynamicPostMutator (Expression expr)
1011 this.type = expr.Type;
1012 this.loc = expr.Location;
1015 public override Expression CreateExpressionTree (ResolveContext ec)
1017 throw new NotImplementedException ("ET");
1020 protected override Expression DoResolve (ResolveContext rc)
1022 eclass = expr.eclass;
1026 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1028 expr.DoResolveLValue (ec, right_side);
1029 return DoResolve (ec);
1032 public override void Emit (EmitContext ec)
1037 public void Emit (EmitContext ec, bool leave_copy)
1039 throw new NotImplementedException ();
1043 // Emits target assignment using unmodified source value
1045 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1048 // Allocate temporary variable to keep original value before it's modified
1050 temp = new LocalTemporary (type);
1054 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1065 public enum Mode : byte {
1072 PreDecrement = IsDecrement,
1073 PostIncrement = IsPost,
1074 PostDecrement = IsPost | IsDecrement
1078 bool is_expr, recurse;
1080 protected Expression expr;
1082 // Holds the real operation
1083 Expression operation;
1085 public UnaryMutator (Mode m, Expression e, Location loc)
1092 public Mode UnaryMutatorMode {
1098 public Expression Expr {
1104 public override Location StartLocation {
1106 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1110 public override bool ContainsEmitWithAwait ()
1112 return expr.ContainsEmitWithAwait ();
1115 public override Expression CreateExpressionTree (ResolveContext ec)
1117 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1120 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1123 // Predefined ++ and -- operators exist for the following types:
1124 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1126 return new TypeSpec[] {
1142 protected override Expression DoResolve (ResolveContext ec)
1144 expr = expr.Resolve (ec);
1149 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1151 // Handle postfix unary operators using local
1152 // temporary variable
1154 if ((mode & Mode.IsPost) != 0)
1155 expr = new DynamicPostMutator (expr);
1157 Arguments args = new Arguments (1);
1158 args.Add (new Argument (expr));
1159 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1162 if (expr.Type.IsNullableType)
1163 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1165 return DoResolveOperation (ec);
1168 protected Expression DoResolveOperation (ResolveContext ec)
1170 eclass = ExprClass.Value;
1173 if (expr is RuntimeValueExpression) {
1176 // Use itself at the top of the stack
1177 operation = new EmptyExpression (type);
1181 // The operand of the prefix/postfix increment decrement operators
1182 // should be an expression that is classified as a variable,
1183 // a property access or an indexer access
1185 // TODO: Move to parser, expr is ATypeNameExpression
1186 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1187 expr = expr.ResolveLValue (ec, expr);
1189 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1193 // Step 1: Try to find a user operator, it has priority over predefined ones
1195 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1196 var methods = MemberCache.GetUserOperator (type, user_op, false);
1198 if (methods != null) {
1199 Arguments args = new Arguments (1);
1200 args.Add (new Argument (expr));
1202 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1203 var method = res.ResolveOperator (ec, ref args);
1207 args[0].Expr = operation;
1208 operation = new UserOperatorCall (method, args, null, loc);
1209 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1214 // Step 2: Try predefined types
1217 Expression source = null;
1218 bool primitive_type;
1221 // Predefined without user conversion first for speed-up
1223 // Predefined ++ and -- operators exist for the following types:
1224 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1226 switch (type.BuiltinType) {
1227 case BuiltinTypeSpec.Type.Byte:
1228 case BuiltinTypeSpec.Type.SByte:
1229 case BuiltinTypeSpec.Type.Short:
1230 case BuiltinTypeSpec.Type.UShort:
1231 case BuiltinTypeSpec.Type.Int:
1232 case BuiltinTypeSpec.Type.UInt:
1233 case BuiltinTypeSpec.Type.Long:
1234 case BuiltinTypeSpec.Type.ULong:
1235 case BuiltinTypeSpec.Type.Char:
1236 case BuiltinTypeSpec.Type.Float:
1237 case BuiltinTypeSpec.Type.Double:
1238 case BuiltinTypeSpec.Type.Decimal:
1240 primitive_type = true;
1243 primitive_type = false;
1245 // ++/-- on pointer variables of all types except void*
1246 if (type.IsPointer) {
1247 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1248 Error_VoidPointerOperation (ec);
1254 Expression best_source = null;
1255 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1256 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1258 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1262 if (best_source == null) {
1263 best_source = source;
1267 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1272 best_source = source;
1276 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1280 source = best_source;
1283 // ++/-- on enum types
1284 if (source == null && type.IsEnum)
1287 if (source == null) {
1288 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1295 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1296 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1297 operation = new Binary (op, source, one);
1298 operation = operation.Resolve (ec);
1299 if (operation == null)
1300 throw new NotImplementedException ("should not be reached");
1302 if (operation.Type != type) {
1304 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1306 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1312 void EmitCode (EmitContext ec, bool is_expr)
1315 this.is_expr = is_expr;
1316 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1319 public override void Emit (EmitContext ec)
1322 // We use recurse to allow ourselfs to be the source
1323 // of an assignment. This little hack prevents us from
1324 // having to allocate another expression
1327 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1335 EmitCode (ec, true);
1338 protected virtual void EmitOperation (EmitContext ec)
1340 operation.Emit (ec);
1343 public override void EmitStatement (EmitContext ec)
1345 EmitCode (ec, false);
1348 public override void FlowAnalysis (FlowAnalysisContext fc)
1350 expr.FlowAnalysis (fc);
1354 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1356 string GetOperatorExpressionTypeName ()
1358 return IsDecrement ? "Decrement" : "Increment";
1362 get { return (mode & Mode.IsDecrement) != 0; }
1366 #if NET_4_0 || MOBILE_DYNAMIC
1367 public override SLE.Expression MakeExpression (BuilderContext ctx)
1369 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1370 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1371 return SLE.Expression.Assign (target, source);
1375 public static string OperName (Mode oper)
1377 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1380 protected override void CloneTo (CloneContext clonectx, Expression t)
1382 UnaryMutator target = (UnaryMutator) t;
1384 target.expr = expr.Clone (clonectx);
1387 public override object Accept (StructuralVisitor visitor)
1389 return visitor.Visit (this);
1395 // Base class for the `is' and `as' operators
1397 public abstract class Probe : Expression
1399 public Expression ProbeType;
1400 protected Expression expr;
1401 protected TypeSpec probe_type_expr;
1403 protected Probe (Expression expr, Expression probe_type, Location l)
1405 ProbeType = probe_type;
1410 public Expression Expr {
1416 public override bool ContainsEmitWithAwait ()
1418 return expr.ContainsEmitWithAwait ();
1421 protected override Expression DoResolve (ResolveContext ec)
1423 probe_type_expr = ProbeType.ResolveAsType (ec);
1424 if (probe_type_expr == null)
1427 expr = expr.Resolve (ec);
1431 if (probe_type_expr.IsStatic) {
1432 ec.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1433 probe_type_expr.GetSignatureForError ());
1437 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1438 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1443 if (expr.Type == InternalType.AnonymousMethod) {
1444 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1452 public override void FlowAnalysis (FlowAnalysisContext fc)
1454 expr.FlowAnalysis (fc);
1457 protected abstract string OperatorName { get; }
1459 protected override void CloneTo (CloneContext clonectx, Expression t)
1461 Probe target = (Probe) t;
1463 target.expr = expr.Clone (clonectx);
1464 target.ProbeType = ProbeType.Clone (clonectx);
1470 /// Implementation of the `is' operator.
1472 public class Is : Probe
1474 Nullable.Unwrap expr_unwrap;
1476 public Is (Expression expr, Expression probe_type, Location l)
1477 : base (expr, probe_type, l)
1481 protected override string OperatorName {
1482 get { return "is"; }
1485 public override Expression CreateExpressionTree (ResolveContext ec)
1487 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1488 expr.CreateExpressionTree (ec),
1489 new TypeOf (probe_type_expr, loc));
1491 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1494 public override void Emit (EmitContext ec)
1496 if (expr_unwrap != null) {
1497 expr_unwrap.EmitCheck (ec);
1503 // Only to make verifier happy
1504 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1505 ec.Emit (OpCodes.Box, expr.Type);
1507 ec.Emit (OpCodes.Isinst, probe_type_expr);
1509 ec.Emit (OpCodes.Cgt_Un);
1512 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1514 if (expr_unwrap != null) {
1515 expr_unwrap.EmitCheck (ec);
1518 ec.Emit (OpCodes.Isinst, probe_type_expr);
1520 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1523 Expression CreateConstantResult (ResolveContext ec, bool result)
1526 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1527 probe_type_expr.GetSignatureForError ());
1529 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1530 probe_type_expr.GetSignatureForError ());
1532 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1535 protected override Expression DoResolve (ResolveContext ec)
1537 if (base.DoResolve (ec) == null)
1540 TypeSpec d = expr.Type;
1541 bool d_is_nullable = false;
1544 // If E is a method group or the null literal, or if the type of E is a reference
1545 // type or a nullable type and the value of E is null, the result is false
1547 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1548 return CreateConstantResult (ec, false);
1550 if (d.IsNullableType) {
1551 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1552 if (!ut.IsGenericParameter) {
1554 d_is_nullable = true;
1558 type = ec.BuiltinTypes.Bool;
1559 eclass = ExprClass.Value;
1560 TypeSpec t = probe_type_expr;
1561 bool t_is_nullable = false;
1562 if (t.IsNullableType) {
1563 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1564 if (!ut.IsGenericParameter) {
1566 t_is_nullable = true;
1573 // D and T are the same value types but D can be null
1575 if (d_is_nullable && !t_is_nullable) {
1576 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1581 // The result is true if D and T are the same value types
1583 return CreateConstantResult (ec, true);
1586 var tp = d as TypeParameterSpec;
1588 return ResolveGenericParameter (ec, t, tp);
1591 // An unboxing conversion exists
1593 if (Convert.ExplicitReferenceConversionExists (d, t))
1597 // open generic type
1599 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1602 var tps = t as TypeParameterSpec;
1604 return ResolveGenericParameter (ec, d, tps);
1606 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1607 ec.Report.Warning (1981, 3, loc,
1608 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1609 OperatorName, t.GetSignatureForError ());
1612 if (TypeManager.IsGenericParameter (d))
1613 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1615 if (TypeSpec.IsValueType (d)) {
1616 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1617 if (d_is_nullable && !t_is_nullable) {
1618 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1622 return CreateConstantResult (ec, true);
1625 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1626 var c = expr as Constant;
1628 return CreateConstantResult (ec, !c.IsNull);
1631 // Do not optimize for imported type or dynamic type
1633 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1634 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1638 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1642 // Turn is check into simple null check for implicitly convertible reference types
1644 return ReducedExpression.Create (
1645 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1649 if (Convert.ExplicitReferenceConversionExists (d, t))
1653 // open generic type
1655 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1660 return CreateConstantResult (ec, false);
1663 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1665 if (t.IsReferenceType) {
1667 return CreateConstantResult (ec, false);
1670 if (expr.Type.IsGenericParameter) {
1671 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1672 return CreateConstantResult (ec, true);
1674 expr = new BoxedCast (expr, d);
1680 public override object Accept (StructuralVisitor visitor)
1682 return visitor.Visit (this);
1687 /// Implementation of the `as' operator.
1689 public class As : Probe {
1690 Expression resolved_type;
1692 public As (Expression expr, Expression probe_type, Location l)
1693 : base (expr, probe_type, l)
1697 protected override string OperatorName {
1698 get { return "as"; }
1701 public override Expression CreateExpressionTree (ResolveContext ec)
1703 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1704 expr.CreateExpressionTree (ec),
1705 new TypeOf (probe_type_expr, loc));
1707 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1710 public override void Emit (EmitContext ec)
1714 ec.Emit (OpCodes.Isinst, type);
1716 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1717 ec.Emit (OpCodes.Unbox_Any, type);
1720 protected override Expression DoResolve (ResolveContext ec)
1722 if (resolved_type == null) {
1723 resolved_type = base.DoResolve (ec);
1725 if (resolved_type == null)
1729 type = probe_type_expr;
1730 eclass = ExprClass.Value;
1731 TypeSpec etype = expr.Type;
1733 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1734 if (TypeManager.IsGenericParameter (type)) {
1735 ec.Report.Error (413, loc,
1736 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1737 probe_type_expr.GetSignatureForError ());
1739 ec.Report.Error (77, loc,
1740 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1741 type.GetSignatureForError ());
1746 if (expr.IsNull && type.IsNullableType) {
1747 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1750 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1751 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1755 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1757 e = EmptyCast.Create (e, type);
1758 return ReducedExpression.Create (e, this).Resolve (ec);
1761 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1762 if (TypeManager.IsGenericParameter (etype))
1763 expr = new BoxedCast (expr, etype);
1768 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1769 expr = new BoxedCast (expr, etype);
1773 if (etype != InternalType.ErrorType) {
1774 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1775 etype.GetSignatureForError (), type.GetSignatureForError ());
1781 public override object Accept (StructuralVisitor visitor)
1783 return visitor.Visit (this);
1788 // This represents a typecast in the source language.
1790 public class Cast : ShimExpression {
1791 Expression target_type;
1793 public Cast (Expression cast_type, Expression expr, Location loc)
1796 this.target_type = cast_type;
1800 public Expression TargetType {
1801 get { return target_type; }
1804 protected override Expression DoResolve (ResolveContext ec)
1806 expr = expr.Resolve (ec);
1810 type = target_type.ResolveAsType (ec);
1814 if (type.IsStatic) {
1815 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1819 if (type.IsPointer && !ec.IsUnsafe) {
1820 UnsafeError (ec, loc);
1823 eclass = ExprClass.Value;
1825 Constant c = expr as Constant;
1827 c = c.Reduce (ec, type);
1832 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1834 return EmptyCast.Create (res, type);
1839 protected override void CloneTo (CloneContext clonectx, Expression t)
1841 Cast target = (Cast) t;
1843 target.target_type = target_type.Clone (clonectx);
1844 target.expr = expr.Clone (clonectx);
1847 public override object Accept (StructuralVisitor visitor)
1849 return visitor.Visit (this);
1853 public class ImplicitCast : ShimExpression
1857 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1860 this.loc = expr.Location;
1862 this.arrayAccess = arrayAccess;
1865 protected override Expression DoResolve (ResolveContext ec)
1867 expr = expr.Resolve (ec);
1872 expr = ConvertExpressionToArrayIndex (ec, expr);
1874 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1881 // C# 2.0 Default value expression
1883 public class DefaultValueExpression : Expression
1887 public DefaultValueExpression (Expression expr, Location loc)
1893 public Expression Expr {
1899 public override bool IsSideEffectFree {
1905 public override bool ContainsEmitWithAwait ()
1910 public override Expression CreateExpressionTree (ResolveContext ec)
1912 Arguments args = new Arguments (2);
1913 args.Add (new Argument (this));
1914 args.Add (new Argument (new TypeOf (type, loc)));
1915 return CreateExpressionFactoryCall (ec, "Constant", args);
1918 protected override Expression DoResolve (ResolveContext ec)
1920 type = expr.ResolveAsType (ec);
1924 if (type.IsStatic) {
1925 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1929 return new NullLiteral (Location).ConvertImplicitly (type);
1931 if (TypeSpec.IsReferenceType (type))
1932 return new NullConstant (type, loc);
1934 Constant c = New.Constantify (type, expr.Location);
1938 eclass = ExprClass.Variable;
1942 public override void Emit (EmitContext ec)
1944 LocalTemporary temp_storage = new LocalTemporary(type);
1946 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1947 ec.Emit(OpCodes.Initobj, type);
1948 temp_storage.Emit(ec);
1949 temp_storage.Release (ec);
1952 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
1953 public override SLE.Expression MakeExpression (BuilderContext ctx)
1955 return SLE.Expression.Default (type.GetMetaInfo ());
1959 protected override void CloneTo (CloneContext clonectx, Expression t)
1961 DefaultValueExpression target = (DefaultValueExpression) t;
1963 target.expr = expr.Clone (clonectx);
1966 public override object Accept (StructuralVisitor visitor)
1968 return visitor.Visit (this);
1973 /// Binary operators
1975 public class Binary : Expression, IDynamicBinder
1977 public class PredefinedOperator
1979 protected readonly TypeSpec left;
1980 protected readonly TypeSpec right;
1981 protected readonly TypeSpec left_unwrap;
1982 protected readonly TypeSpec right_unwrap;
1983 public readonly Operator OperatorsMask;
1984 public TypeSpec ReturnType;
1986 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1987 : this (ltype, rtype, op_mask, ltype)
1991 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1992 : this (type, type, op_mask, return_type)
1996 public PredefinedOperator (TypeSpec type, Operator op_mask)
1997 : this (type, type, op_mask, type)
2001 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2003 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2004 throw new InternalErrorException ("Only masked values can be used");
2006 if ((op_mask & Operator.NullableMask) != 0) {
2007 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2008 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2010 left_unwrap = ltype;
2011 right_unwrap = rtype;
2016 this.OperatorsMask = op_mask;
2017 this.ReturnType = return_type;
2020 public bool IsLifted {
2022 return (OperatorsMask & Operator.NullableMask) != 0;
2026 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2030 var left_expr = b.left;
2031 var right_expr = b.right;
2033 b.type = ReturnType;
2036 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2037 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2038 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2041 if (right_expr.IsNull) {
2042 if ((b.oper & Operator.EqualityMask) != 0) {
2043 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2044 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2045 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2046 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2047 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2049 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2050 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2052 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2053 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2055 return b.CreateLiftedValueTypeResult (rc, left);
2057 } else if (left_expr.IsNull) {
2058 if ((b.oper & Operator.EqualityMask) != 0) {
2059 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2060 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2061 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2062 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2063 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2065 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2066 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2068 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2069 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2071 return b.CreateLiftedValueTypeResult (rc, right);
2077 // A user operators does not support multiple user conversions, but decimal type
2078 // is considered to be predefined type therefore we apply predefined operators rules
2079 // and then look for decimal user-operator implementation
2081 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2082 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2083 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2085 return b.ResolveUserOperator (rc, b.left, b.right);
2088 c = right_expr as Constant;
2090 if (c.IsDefaultValue) {
2094 // (expr + 0) to expr
2095 // (expr - 0) to expr
2096 // (bool? | false) to bool?
2098 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2099 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2100 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2101 return ReducedExpression.Create (b.left, b).Resolve (rc);
2105 // Optimizes (value &/&& 0) to 0
2107 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2108 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2109 return ReducedExpression.Create (side_effect, b);
2113 // Optimizes (bool? & true) to bool?
2115 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2116 return ReducedExpression.Create (b.left, b).Resolve (rc);
2120 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2121 return ReducedExpression.Create (b.left, b).Resolve (rc);
2123 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2124 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2128 c = b.left as Constant;
2130 if (c.IsDefaultValue) {
2134 // (0 + expr) to expr
2135 // (false | bool?) to bool?
2137 if (b.oper == Operator.Addition ||
2138 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2139 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2140 return ReducedExpression.Create (b.right, b).Resolve (rc);
2144 // Optimizes (false && expr) to false
2146 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2147 // No rhs side-effects
2148 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2149 return ReducedExpression.Create (c, b);
2153 // Optimizes (0 & value) to 0
2155 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2156 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2157 return ReducedExpression.Create (side_effect, b);
2161 // Optimizes (true & bool?) to bool?
2163 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2164 return ReducedExpression.Create (b.right, b).Resolve (rc);
2168 // Optimizes (true || expr) to true
2170 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2171 // No rhs side-effects
2172 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2173 return ReducedExpression.Create (c, b);
2177 if (b.oper == Operator.Multiply && c.IsOneInteger)
2178 return ReducedExpression.Create (b.right, b).Resolve (rc);
2182 var lifted = new Nullable.LiftedBinaryOperator (b);
2184 TypeSpec ltype, rtype;
2185 if (b.left.Type.IsNullableType) {
2186 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2187 ltype = left_unwrap;
2192 if (b.right.Type.IsNullableType) {
2193 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2194 rtype = right_unwrap;
2199 lifted.Left = b.left.IsNull ?
2201 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2203 lifted.Right = b.right.IsNull ?
2205 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2207 return lifted.Resolve (rc);
2210 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2211 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2216 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2219 // We are dealing with primitive types only
2221 return left == ltype && ltype == rtype;
2224 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2227 if (left == lexpr.Type && right == rexpr.Type)
2230 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2231 Convert.ImplicitConversionExists (ec, rexpr, right);
2234 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2236 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2237 return best_operator;
2239 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2243 if (left != null && best_operator.left != null) {
2244 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2248 // When second argument is same as the first one, the result is same
2250 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2251 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2254 if (result == 0 || result > 2)
2257 return result == 1 ? best_operator : this;
2261 sealed class PredefinedStringOperator : PredefinedOperator
2263 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2264 : base (type, type, op_mask, retType)
2268 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2269 : base (ltype, rtype, op_mask, retType)
2273 public override Expression ConvertResult (ResolveContext ec, Binary b)
2276 // Use original expression for nullable arguments
2278 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2280 b.left = unwrap.Original;
2282 unwrap = b.right as Nullable.Unwrap;
2284 b.right = unwrap.Original;
2286 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2287 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2290 // Start a new concat expression using converted expression
2292 return StringConcat.Create (ec, b.left, b.right, b.loc);
2296 sealed class PredefinedEqualityOperator : PredefinedOperator
2298 MethodSpec equal_method, inequal_method;
2300 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2301 : base (arg, arg, Operator.EqualityMask, retType)
2305 public override Expression ConvertResult (ResolveContext ec, Binary b)
2307 b.type = ReturnType;
2309 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2310 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2312 Arguments args = new Arguments (2);
2313 args.Add (new Argument (b.left));
2314 args.Add (new Argument (b.right));
2317 if (b.oper == Operator.Equality) {
2318 if (equal_method == null) {
2319 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2320 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2321 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2322 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2324 throw new NotImplementedException (left.GetSignatureForError ());
2327 method = equal_method;
2329 if (inequal_method == null) {
2330 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2331 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2332 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2333 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2335 throw new NotImplementedException (left.GetSignatureForError ());
2338 method = inequal_method;
2341 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2345 class PredefinedPointerOperator : PredefinedOperator
2347 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2348 : base (ltype, rtype, op_mask)
2352 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2353 : base (ltype, rtype, op_mask, retType)
2357 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2358 : base (type, op_mask, return_type)
2362 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2365 if (!lexpr.Type.IsPointer)
2368 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2372 if (right == null) {
2373 if (!rexpr.Type.IsPointer)
2376 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2383 public override Expression ConvertResult (ResolveContext ec, Binary b)
2386 b.left = EmptyCast.Create (b.left, left);
2387 } else if (right != null) {
2388 b.right = EmptyCast.Create (b.right, right);
2391 TypeSpec r_type = ReturnType;
2392 Expression left_arg, right_arg;
2393 if (r_type == null) {
2396 right_arg = b.right;
2397 r_type = b.left.Type;
2401 r_type = b.right.Type;
2405 right_arg = b.right;
2408 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2413 public enum Operator {
2414 Multiply = 0 | ArithmeticMask,
2415 Division = 1 | ArithmeticMask,
2416 Modulus = 2 | ArithmeticMask,
2417 Addition = 3 | ArithmeticMask | AdditionMask,
2418 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2420 LeftShift = 5 | ShiftMask,
2421 RightShift = 6 | ShiftMask,
2423 LessThan = 7 | ComparisonMask | RelationalMask,
2424 GreaterThan = 8 | ComparisonMask | RelationalMask,
2425 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2426 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2427 Equality = 11 | ComparisonMask | EqualityMask,
2428 Inequality = 12 | ComparisonMask | EqualityMask,
2430 BitwiseAnd = 13 | BitwiseMask,
2431 ExclusiveOr = 14 | BitwiseMask,
2432 BitwiseOr = 15 | BitwiseMask,
2434 LogicalAnd = 16 | LogicalMask,
2435 LogicalOr = 17 | LogicalMask,
2440 ValuesOnlyMask = ArithmeticMask - 1,
2441 ArithmeticMask = 1 << 5,
2443 ComparisonMask = 1 << 7,
2444 EqualityMask = 1 << 8,
2445 BitwiseMask = 1 << 9,
2446 LogicalMask = 1 << 10,
2447 AdditionMask = 1 << 11,
2448 SubtractionMask = 1 << 12,
2449 RelationalMask = 1 << 13,
2451 DecomposedMask = 1 << 19,
2452 NullableMask = 1 << 20,
2462 readonly Operator oper;
2463 Expression left, right;
2465 ConvCast.Mode enum_conversion;
2467 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2468 : this (oper, left, right)
2471 state |= State.Compound;
2474 public Binary (Operator oper, Expression left, Expression right)
2479 this.loc = left.Location;
2484 public bool IsCompound {
2486 return (state & State.Compound) != 0;
2490 public Operator Oper {
2496 public Expression Left {
2502 public Expression Right {
2508 public override Location StartLocation {
2510 return left.StartLocation;
2517 /// Returns a stringified representation of the Operator
2519 string OperName (Operator oper)
2523 case Operator.Multiply:
2526 case Operator.Division:
2529 case Operator.Modulus:
2532 case Operator.Addition:
2535 case Operator.Subtraction:
2538 case Operator.LeftShift:
2541 case Operator.RightShift:
2544 case Operator.LessThan:
2547 case Operator.GreaterThan:
2550 case Operator.LessThanOrEqual:
2553 case Operator.GreaterThanOrEqual:
2556 case Operator.Equality:
2559 case Operator.Inequality:
2562 case Operator.BitwiseAnd:
2565 case Operator.BitwiseOr:
2568 case Operator.ExclusiveOr:
2571 case Operator.LogicalOr:
2574 case Operator.LogicalAnd:
2578 s = oper.ToString ();
2588 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2590 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2593 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2595 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2599 l = left.Type.GetSignatureForError ();
2600 r = right.Type.GetSignatureForError ();
2602 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2606 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2608 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2611 public override void FlowAnalysis (FlowAnalysisContext fc)
2613 if ((oper & Operator.LogicalMask) == 0) {
2614 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
2615 left.FlowAnalysis (fc);
2616 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
2617 right.FlowAnalysis (fc);
2622 // Optimized version when on-true/on-false data are not needed
2624 bool set_on_true_false;
2625 if (fc.DefiniteAssignmentOnTrue == null && fc.DefiniteAssignmentOnFalse == null) {
2626 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
2627 set_on_true_false = false;
2629 set_on_true_false = true;
2632 left.FlowAnalysis (fc);
2633 var left_fc = fc.DefiniteAssignment;
2634 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
2635 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
2637 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
2638 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
2639 right.FlowAnalysis (fc);
2640 fc.DefiniteAssignment = left_fc;
2642 if (!set_on_true_false) {
2643 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = null;
2647 if (oper == Operator.LogicalOr) {
2648 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue);
2649 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
2651 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
2652 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet (left_fc_onfalse);
2657 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2659 string GetOperatorExpressionTypeName ()
2662 case Operator.Addition:
2663 return IsCompound ? "AddAssign" : "Add";
2664 case Operator.BitwiseAnd:
2665 return IsCompound ? "AndAssign" : "And";
2666 case Operator.BitwiseOr:
2667 return IsCompound ? "OrAssign" : "Or";
2668 case Operator.Division:
2669 return IsCompound ? "DivideAssign" : "Divide";
2670 case Operator.ExclusiveOr:
2671 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2672 case Operator.Equality:
2674 case Operator.GreaterThan:
2675 return "GreaterThan";
2676 case Operator.GreaterThanOrEqual:
2677 return "GreaterThanOrEqual";
2678 case Operator.Inequality:
2680 case Operator.LeftShift:
2681 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2682 case Operator.LessThan:
2684 case Operator.LessThanOrEqual:
2685 return "LessThanOrEqual";
2686 case Operator.LogicalAnd:
2688 case Operator.LogicalOr:
2690 case Operator.Modulus:
2691 return IsCompound ? "ModuloAssign" : "Modulo";
2692 case Operator.Multiply:
2693 return IsCompound ? "MultiplyAssign" : "Multiply";
2694 case Operator.RightShift:
2695 return IsCompound ? "RightShiftAssign" : "RightShift";
2696 case Operator.Subtraction:
2697 return IsCompound ? "SubtractAssign" : "Subtract";
2699 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2703 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2706 case Operator.Addition:
2707 return CSharp.Operator.OpType.Addition;
2708 case Operator.BitwiseAnd:
2709 case Operator.LogicalAnd:
2710 return CSharp.Operator.OpType.BitwiseAnd;
2711 case Operator.BitwiseOr:
2712 case Operator.LogicalOr:
2713 return CSharp.Operator.OpType.BitwiseOr;
2714 case Operator.Division:
2715 return CSharp.Operator.OpType.Division;
2716 case Operator.Equality:
2717 return CSharp.Operator.OpType.Equality;
2718 case Operator.ExclusiveOr:
2719 return CSharp.Operator.OpType.ExclusiveOr;
2720 case Operator.GreaterThan:
2721 return CSharp.Operator.OpType.GreaterThan;
2722 case Operator.GreaterThanOrEqual:
2723 return CSharp.Operator.OpType.GreaterThanOrEqual;
2724 case Operator.Inequality:
2725 return CSharp.Operator.OpType.Inequality;
2726 case Operator.LeftShift:
2727 return CSharp.Operator.OpType.LeftShift;
2728 case Operator.LessThan:
2729 return CSharp.Operator.OpType.LessThan;
2730 case Operator.LessThanOrEqual:
2731 return CSharp.Operator.OpType.LessThanOrEqual;
2732 case Operator.Modulus:
2733 return CSharp.Operator.OpType.Modulus;
2734 case Operator.Multiply:
2735 return CSharp.Operator.OpType.Multiply;
2736 case Operator.RightShift:
2737 return CSharp.Operator.OpType.RightShift;
2738 case Operator.Subtraction:
2739 return CSharp.Operator.OpType.Subtraction;
2741 throw new InternalErrorException (op.ToString ());
2745 public override bool ContainsEmitWithAwait ()
2747 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2750 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2755 case Operator.Multiply:
2756 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2757 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2758 opcode = OpCodes.Mul_Ovf;
2759 else if (!IsFloat (l))
2760 opcode = OpCodes.Mul_Ovf_Un;
2762 opcode = OpCodes.Mul;
2764 opcode = OpCodes.Mul;
2768 case Operator.Division:
2770 opcode = OpCodes.Div_Un;
2772 opcode = OpCodes.Div;
2775 case Operator.Modulus:
2777 opcode = OpCodes.Rem_Un;
2779 opcode = OpCodes.Rem;
2782 case Operator.Addition:
2783 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2784 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2785 opcode = OpCodes.Add_Ovf;
2786 else if (!IsFloat (l))
2787 opcode = OpCodes.Add_Ovf_Un;
2789 opcode = OpCodes.Add;
2791 opcode = OpCodes.Add;
2794 case Operator.Subtraction:
2795 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2796 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2797 opcode = OpCodes.Sub_Ovf;
2798 else if (!IsFloat (l))
2799 opcode = OpCodes.Sub_Ovf_Un;
2801 opcode = OpCodes.Sub;
2803 opcode = OpCodes.Sub;
2806 case Operator.RightShift:
2807 if (!(right is IntConstant)) {
2808 ec.EmitInt (GetShiftMask (l));
2809 ec.Emit (OpCodes.And);
2813 opcode = OpCodes.Shr_Un;
2815 opcode = OpCodes.Shr;
2818 case Operator.LeftShift:
2819 if (!(right is IntConstant)) {
2820 ec.EmitInt (GetShiftMask (l));
2821 ec.Emit (OpCodes.And);
2824 opcode = OpCodes.Shl;
2827 case Operator.Equality:
2828 opcode = OpCodes.Ceq;
2831 case Operator.Inequality:
2832 ec.Emit (OpCodes.Ceq);
2835 opcode = OpCodes.Ceq;
2838 case Operator.LessThan:
2840 opcode = OpCodes.Clt_Un;
2842 opcode = OpCodes.Clt;
2845 case Operator.GreaterThan:
2847 opcode = OpCodes.Cgt_Un;
2849 opcode = OpCodes.Cgt;
2852 case Operator.LessThanOrEqual:
2853 if (IsUnsigned (l) || IsFloat (l))
2854 ec.Emit (OpCodes.Cgt_Un);
2856 ec.Emit (OpCodes.Cgt);
2859 opcode = OpCodes.Ceq;
2862 case Operator.GreaterThanOrEqual:
2863 if (IsUnsigned (l) || IsFloat (l))
2864 ec.Emit (OpCodes.Clt_Un);
2866 ec.Emit (OpCodes.Clt);
2870 opcode = OpCodes.Ceq;
2873 case Operator.BitwiseOr:
2874 opcode = OpCodes.Or;
2877 case Operator.BitwiseAnd:
2878 opcode = OpCodes.And;
2881 case Operator.ExclusiveOr:
2882 opcode = OpCodes.Xor;
2886 throw new InternalErrorException (oper.ToString ());
2892 static int GetShiftMask (TypeSpec type)
2894 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2897 static bool IsUnsigned (TypeSpec t)
2899 switch (t.BuiltinType) {
2900 case BuiltinTypeSpec.Type.Char:
2901 case BuiltinTypeSpec.Type.UInt:
2902 case BuiltinTypeSpec.Type.ULong:
2903 case BuiltinTypeSpec.Type.UShort:
2904 case BuiltinTypeSpec.Type.Byte:
2911 static bool IsFloat (TypeSpec t)
2913 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2916 public Expression ResolveOperator (ResolveContext rc)
2918 eclass = ExprClass.Value;
2920 TypeSpec l = left.Type;
2921 TypeSpec r = right.Type;
2923 bool primitives_only = false;
2926 // Handles predefined primitive types
2928 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2929 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2930 if ((oper & Operator.ShiftMask) == 0) {
2931 if (!DoBinaryOperatorPromotion (rc))
2934 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2938 if (l.IsPointer || r.IsPointer)
2939 return ResolveOperatorPointer (rc, l, r);
2942 expr = ResolveUserOperator (rc, left, right);
2947 bool lenum = l.IsEnum;
2948 bool renum = r.IsEnum;
2949 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2953 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2954 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2959 if ((oper & Operator.BitwiseMask) != 0) {
2960 expr = EmptyCast.Create (expr, type);
2961 AddEnumResultCast (type);
2963 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2964 expr = OptimizeAndOperation (expr);
2968 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
2969 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
2972 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2973 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2977 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2980 // We cannot break here there is also Enum + String possible match
2981 // which is not ambiguous with predefined enum operators
2984 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
2985 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
2989 } else if (l.IsDelegate || r.IsDelegate) {
2993 expr = ResolveOperatorDelegate (rc, l, r);
2995 // TODO: Can this be ambiguous
3003 // Equality operators are more complicated
3005 if ((oper & Operator.EqualityMask) != 0) {
3006 return ResolveEquality (rc, l, r, primitives_only);
3009 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3013 if (primitives_only)
3017 // Lifted operators have lower priority
3019 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3022 static bool IsEnumOrNullableEnum (TypeSpec type)
3024 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3028 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3029 // if 'left' is not an enumeration constant, create one from the type of 'right'
3030 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3033 case Operator.BitwiseOr:
3034 case Operator.BitwiseAnd:
3035 case Operator.ExclusiveOr:
3036 case Operator.Equality:
3037 case Operator.Inequality:
3038 case Operator.LessThan:
3039 case Operator.LessThanOrEqual:
3040 case Operator.GreaterThan:
3041 case Operator.GreaterThanOrEqual:
3042 if (left.Type.IsEnum)
3045 if (left.IsZeroInteger)
3046 return left.Reduce (ec, right.Type);
3050 case Operator.Addition:
3051 case Operator.Subtraction:
3054 case Operator.Multiply:
3055 case Operator.Division:
3056 case Operator.Modulus:
3057 case Operator.LeftShift:
3058 case Operator.RightShift:
3059 if (right.Type.IsEnum || left.Type.IsEnum)
3068 // The `|' operator used on types which were extended is dangerous
3070 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3072 OpcodeCast lcast = left as OpcodeCast;
3073 if (lcast != null) {
3074 if (IsUnsigned (lcast.UnderlyingType))
3078 OpcodeCast rcast = right as OpcodeCast;
3079 if (rcast != null) {
3080 if (IsUnsigned (rcast.UnderlyingType))
3084 if (lcast == null && rcast == null)
3087 // FIXME: consider constants
3089 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3090 ec.Report.Warning (675, 3, loc,
3091 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3092 ltype.GetSignatureForError ());
3095 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3097 return new PredefinedOperator[] {
3099 // Pointer arithmetic:
3101 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3102 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3103 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3104 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3106 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3107 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3108 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3109 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3112 // T* operator + (int y, T* x);
3113 // T* operator + (uint y, T *x);
3114 // T* operator + (long y, T *x);
3115 // T* operator + (ulong y, T *x);
3117 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3118 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3119 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3120 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3123 // long operator - (T* x, T *y)
3125 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3129 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3131 TypeSpec bool_type = types.Bool;
3134 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3135 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3136 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3137 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3138 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3139 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3140 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3142 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3143 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3144 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3145 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3146 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3147 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3148 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3150 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3151 // Remaining string operators are in lifted tables
3153 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3155 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3156 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3157 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3161 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3163 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3164 if (nullable == null)
3165 return new PredefinedOperator [0];
3167 var types = module.Compiler.BuiltinTypes;
3168 var bool_type = types.Bool;
3170 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3171 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3172 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3173 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3174 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3175 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3176 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3177 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3180 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3181 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3182 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3183 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3184 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3185 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3186 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3188 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3189 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3190 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3191 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3192 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3193 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3194 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3196 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3198 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3199 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3200 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3203 // Not strictly lifted but need to be in second group otherwise expressions like
3204 // int + null would resolve to +(object, string) instead of +(int?, int?)
3206 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3207 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3212 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3214 TypeSpec bool_type = types.Bool;
3217 new PredefinedEqualityOperator (types.String, bool_type),
3218 new PredefinedEqualityOperator (types.Delegate, bool_type),
3219 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3220 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3221 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3222 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3223 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3224 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3225 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3226 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3230 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3232 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3234 if (nullable == null)
3235 return new PredefinedOperator [0];
3237 var types = module.Compiler.BuiltinTypes;
3238 var bool_type = types.Bool;
3239 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3240 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3241 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3242 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3243 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3244 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3245 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3246 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3249 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3250 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3251 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3252 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3253 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3254 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3255 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3256 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3261 // 7.2.6.2 Binary numeric promotions
3263 bool DoBinaryOperatorPromotion (ResolveContext rc)
3265 TypeSpec ltype = left.Type;
3266 if (ltype.IsNullableType) {
3267 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3271 // This is numeric promotion code only
3273 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3276 TypeSpec rtype = right.Type;
3277 if (rtype.IsNullableType) {
3278 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3281 var lb = ltype.BuiltinType;
3282 var rb = rtype.BuiltinType;
3286 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3287 type = rc.BuiltinTypes.Decimal;
3288 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3289 type = rc.BuiltinTypes.Double;
3290 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3291 type = rc.BuiltinTypes.Float;
3292 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3293 type = rc.BuiltinTypes.ULong;
3295 if (IsSignedType (lb)) {
3296 expr = ConvertSignedConstant (left, type);
3300 } else if (IsSignedType (rb)) {
3301 expr = ConvertSignedConstant (right, type);
3307 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3308 type = rc.BuiltinTypes.Long;
3309 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3310 type = rc.BuiltinTypes.UInt;
3312 if (IsSignedType (lb)) {
3313 expr = ConvertSignedConstant (left, type);
3315 type = rc.BuiltinTypes.Long;
3316 } else if (IsSignedType (rb)) {
3317 expr = ConvertSignedConstant (right, type);
3319 type = rc.BuiltinTypes.Long;
3322 type = rc.BuiltinTypes.Int;
3325 if (ltype != type) {
3326 expr = PromoteExpression (rc, left, type);
3333 if (rtype != type) {
3334 expr = PromoteExpression (rc, right, type);
3344 static bool IsSignedType (BuiltinTypeSpec.Type type)
3347 case BuiltinTypeSpec.Type.Int:
3348 case BuiltinTypeSpec.Type.Short:
3349 case BuiltinTypeSpec.Type.SByte:
3350 case BuiltinTypeSpec.Type.Long:
3357 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3359 var c = expr as Constant;
3363 return c.ConvertImplicitly (type);
3366 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3368 if (expr.Type.IsNullableType) {
3369 return Convert.ImplicitConversionStandard (rc, expr,
3370 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3373 var c = expr as Constant;
3375 return c.ConvertImplicitly (type);
3377 return Convert.ImplicitNumericConversion (expr, type);
3380 protected override Expression DoResolve (ResolveContext ec)
3385 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3386 left = ((ParenthesizedExpression) left).Expr;
3387 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3391 if (left.eclass == ExprClass.Type) {
3392 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3396 left = left.Resolve (ec);
3401 right = right.Resolve (ec);
3405 Constant lc = left as Constant;
3406 Constant rc = right as Constant;
3408 // The conversion rules are ignored in enum context but why
3409 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3410 lc = EnumLiftUp (ec, lc, rc);
3412 rc = EnumLiftUp (ec, rc, lc);
3415 if (rc != null && lc != null) {
3416 int prev_e = ec.Report.Errors;
3417 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3418 if (e != null || ec.Report.Errors != prev_e)
3422 // Comparison warnings
3423 if ((oper & Operator.ComparisonMask) != 0) {
3424 if (left.Equals (right)) {
3425 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3427 CheckOutOfRangeComparison (ec, lc, right.Type);
3428 CheckOutOfRangeComparison (ec, rc, left.Type);
3431 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3432 return DoResolveDynamic (ec);
3434 return DoResolveCore (ec, left, right);
3437 Expression DoResolveDynamic (ResolveContext rc)
3440 var rt = right.Type;
3441 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3442 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3443 Error_OperatorCannotBeApplied (rc, left, right);
3450 // Special handling for logical boolean operators which require rhs not to be
3451 // evaluated based on lhs value
3453 if ((oper & Operator.LogicalMask) != 0) {
3454 Expression cond_left, cond_right, expr;
3456 args = new Arguments (2);
3458 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3459 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3461 var cond_args = new Arguments (1);
3462 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3465 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3466 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3468 left = temp.CreateReferenceExpression (rc, loc);
3469 if (oper == Operator.LogicalAnd) {
3470 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3473 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3477 args.Add (new Argument (left));
3478 args.Add (new Argument (right));
3479 cond_right = new DynamicExpressionStatement (this, args, loc);
3481 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3483 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
3484 rc.Report.Error (7083, left.Location,
3485 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
3486 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
3490 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3491 args.Add (new Argument (right));
3492 right = new DynamicExpressionStatement (this, args, loc);
3495 // bool && dynamic => (temp = left) ? temp && right : temp;
3496 // bool || dynamic => (temp = left) ? temp : temp || right;
3498 if (oper == Operator.LogicalAnd) {
3500 cond_right = temp.CreateReferenceExpression (rc, loc);
3502 cond_left = temp.CreateReferenceExpression (rc, loc);
3506 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3509 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3512 args = new Arguments (2);
3513 args.Add (new Argument (left));
3514 args.Add (new Argument (right));
3515 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3518 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3520 Expression expr = ResolveOperator (ec);
3522 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3524 if (left == null || right == null)
3525 throw new InternalErrorException ("Invalid conversion");
3527 if (oper == Operator.BitwiseOr)
3528 CheckBitwiseOrOnSignExtended (ec);
3533 public override SLE.Expression MakeExpression (BuilderContext ctx)
3535 return MakeExpression (ctx, left, right);
3538 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3540 var le = left.MakeExpression (ctx);
3541 var re = right.MakeExpression (ctx);
3542 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3545 case Operator.Addition:
3546 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3547 case Operator.BitwiseAnd:
3548 return SLE.Expression.And (le, re);
3549 case Operator.BitwiseOr:
3550 return SLE.Expression.Or (le, re);
3551 case Operator.Division:
3552 return SLE.Expression.Divide (le, re);
3553 case Operator.Equality:
3554 return SLE.Expression.Equal (le, re);
3555 case Operator.ExclusiveOr:
3556 return SLE.Expression.ExclusiveOr (le, re);
3557 case Operator.GreaterThan:
3558 return SLE.Expression.GreaterThan (le, re);
3559 case Operator.GreaterThanOrEqual:
3560 return SLE.Expression.GreaterThanOrEqual (le, re);
3561 case Operator.Inequality:
3562 return SLE.Expression.NotEqual (le, re);
3563 case Operator.LeftShift:
3564 return SLE.Expression.LeftShift (le, re);
3565 case Operator.LessThan:
3566 return SLE.Expression.LessThan (le, re);
3567 case Operator.LessThanOrEqual:
3568 return SLE.Expression.LessThanOrEqual (le, re);
3569 case Operator.LogicalAnd:
3570 return SLE.Expression.AndAlso (le, re);
3571 case Operator.LogicalOr:
3572 return SLE.Expression.OrElse (le, re);
3573 case Operator.Modulus:
3574 return SLE.Expression.Modulo (le, re);
3575 case Operator.Multiply:
3576 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3577 case Operator.RightShift:
3578 return SLE.Expression.RightShift (le, re);
3579 case Operator.Subtraction:
3580 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3582 throw new NotImplementedException (oper.ToString ());
3587 // D operator + (D x, D y)
3588 // D operator - (D x, D y)
3590 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3592 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3594 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3595 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3600 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3601 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3611 MethodSpec method = null;
3612 Arguments args = new Arguments (2);
3613 args.Add (new Argument (left));
3614 args.Add (new Argument (right));
3616 if (oper == Operator.Addition) {
3617 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3618 } else if (oper == Operator.Subtraction) {
3619 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3623 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3625 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3626 return new ClassCast (expr, l);
3630 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3632 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3635 // bool operator == (E x, E y);
3636 // bool operator != (E x, E y);
3637 // bool operator < (E x, E y);
3638 // bool operator > (E x, E y);
3639 // bool operator <= (E x, E y);
3640 // bool operator >= (E x, E y);
3642 // E operator & (E x, E y);
3643 // E operator | (E x, E y);
3644 // E operator ^ (E x, E y);
3647 if ((oper & Operator.ComparisonMask) != 0) {
3648 type = rc.BuiltinTypes.Bool;
3654 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3660 if (ltype == rtype) {
3664 var lifted = new Nullable.LiftedBinaryOperator (this);
3666 lifted.Right = right;
3667 return lifted.Resolve (rc);
3670 if (renum && !ltype.IsNullableType) {
3671 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3676 } else if (lenum && !rtype.IsNullableType) {
3677 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3685 // Now try lifted version of predefined operator
3687 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3688 if (nullable_type != null) {
3689 if (renum && !ltype.IsNullableType) {
3690 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3692 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3695 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3698 if ((oper & Operator.BitwiseMask) != 0)
3702 if ((oper & Operator.BitwiseMask) != 0)
3703 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3705 return CreateLiftedValueTypeResult (rc, rtype);
3709 var lifted = new Nullable.LiftedBinaryOperator (this);
3711 lifted.Right = right;
3712 return lifted.Resolve (rc);
3714 } else if (lenum && !rtype.IsNullableType) {
3715 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3717 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3720 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3723 if ((oper & Operator.BitwiseMask) != 0)
3727 if ((oper & Operator.BitwiseMask) != 0)
3728 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3730 return CreateLiftedValueTypeResult (rc, ltype);
3734 var lifted = new Nullable.LiftedBinaryOperator (this);
3736 lifted.Right = expr;
3737 return lifted.Resolve (rc);
3739 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3741 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3742 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3744 if ((oper & Operator.RelationalMask) != 0)
3745 return CreateLiftedValueTypeResult (rc, rtype);
3747 if ((oper & Operator.BitwiseMask) != 0)
3748 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3750 // Equality operators are valid between E? and null
3753 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3759 var lifted = new Nullable.LiftedBinaryOperator (this);
3761 lifted.Right = right;
3762 return lifted.Resolve (rc);
3764 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3766 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3767 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3769 if ((oper & Operator.RelationalMask) != 0)
3770 return CreateLiftedValueTypeResult (rc, ltype);
3772 if ((oper & Operator.BitwiseMask) != 0)
3773 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3775 // Equality operators are valid between E? and null
3778 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3784 var lifted = new Nullable.LiftedBinaryOperator (this);
3786 lifted.Right = expr;
3787 return lifted.Resolve (rc);
3795 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
3797 TypeSpec underlying_type;
3798 if (expr.Type.IsNullableType) {
3799 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3801 underlying_type = EnumSpec.GetUnderlyingType (nt);
3803 underlying_type = nt;
3804 } else if (expr.Type.IsEnum) {
3805 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3807 underlying_type = expr.Type;
3810 switch (underlying_type.BuiltinType) {
3811 case BuiltinTypeSpec.Type.SByte:
3812 case BuiltinTypeSpec.Type.Byte:
3813 case BuiltinTypeSpec.Type.Short:
3814 case BuiltinTypeSpec.Type.UShort:
3815 underlying_type = rc.BuiltinTypes.Int;
3819 if (expr.Type.IsNullableType || liftType)
3820 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3822 if (expr.Type == underlying_type)
3825 return EmptyCast.Create (expr, underlying_type);
3828 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3831 // U operator - (E e, E f)
3832 // E operator - (E e, U x) // Internal decomposition operator
3833 // E operator - (U x, E e) // Internal decomposition operator
3835 // E operator + (E e, U x)
3836 // E operator + (U x, E e)
3845 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3851 if (!enum_type.IsNullableType) {
3852 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3854 if (oper == Operator.Subtraction)
3855 expr = ConvertEnumSubtractionResult (rc, expr);
3857 expr = ConvertEnumAdditionalResult (expr, enum_type);
3859 AddEnumResultCast (expr.Type);
3864 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3867 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3869 if (oper == Operator.Subtraction)
3870 expr = ConvertEnumSubtractionResult (rc, expr);
3872 expr = ConvertEnumAdditionalResult (expr, enum_type);
3874 AddEnumResultCast (expr.Type);
3880 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3882 return EmptyCast.Create (expr, enumType);
3885 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3888 // Enumeration subtraction has different result type based on
3891 TypeSpec result_type;
3892 if (left.Type == right.Type) {
3893 var c = right as EnumConstant;
3894 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
3896 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3897 // E which is not what expressions E - 1 or 0 - E return
3899 result_type = left.Type;
3901 result_type = left.Type.IsNullableType ?
3902 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3903 EnumSpec.GetUnderlyingType (left.Type);
3906 if (IsEnumOrNullableEnum (left.Type)) {
3907 result_type = left.Type;
3909 result_type = right.Type;
3912 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3913 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3916 return EmptyCast.Create (expr, result_type);
3919 void AddEnumResultCast (TypeSpec type)
3921 if (type.IsNullableType)
3922 type = Nullable.NullableInfo.GetUnderlyingType (type);
3925 type = EnumSpec.GetUnderlyingType (type);
3927 switch (type.BuiltinType) {
3928 case BuiltinTypeSpec.Type.SByte:
3929 enum_conversion = ConvCast.Mode.I4_I1;
3931 case BuiltinTypeSpec.Type.Byte:
3932 enum_conversion = ConvCast.Mode.I4_U1;
3934 case BuiltinTypeSpec.Type.Short:
3935 enum_conversion = ConvCast.Mode.I4_I2;
3937 case BuiltinTypeSpec.Type.UShort:
3938 enum_conversion = ConvCast.Mode.I4_U2;
3944 // Equality operators rules
3946 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3949 type = ec.BuiltinTypes.Bool;
3950 bool no_arg_conv = false;
3952 if (!primitives_only) {
3955 // a, Both operands are reference-type values or the value null
3956 // b, One operand is a value of type T where T is a type-parameter and
3957 // the other operand is the value null. Furthermore T does not have the
3958 // value type constraint
3960 // LAMESPEC: Very confusing details in the specification, basically any
3961 // reference like type-parameter is allowed
3963 var tparam_l = l as TypeParameterSpec;
3964 var tparam_r = r as TypeParameterSpec;
3965 if (tparam_l != null) {
3966 if (right is NullLiteral) {
3967 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3970 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3974 if (!tparam_l.IsReferenceType)
3977 l = tparam_l.GetEffectiveBase ();
3978 left = new BoxedCast (left, l);
3979 } else if (left is NullLiteral && tparam_r == null) {
3980 if (TypeSpec.IsReferenceType (r))
3983 if (r.Kind == MemberKind.InternalCompilerType)
3987 if (tparam_r != null) {
3988 if (left is NullLiteral) {
3989 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3992 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3996 if (!tparam_r.IsReferenceType)
3999 r = tparam_r.GetEffectiveBase ();
4000 right = new BoxedCast (right, r);
4001 } else if (right is NullLiteral) {
4002 if (TypeSpec.IsReferenceType (l))
4005 if (l.Kind == MemberKind.InternalCompilerType)
4010 // LAMESPEC: method groups can be compared when they convert to other side delegate
4013 if (right.eclass == ExprClass.MethodGroup) {
4014 result = Convert.ImplicitConversion (ec, right, l, loc);
4020 } else if (r.IsDelegate && l != r) {
4023 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4024 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4031 no_arg_conv = l == r && !l.IsStruct;
4036 // bool operator != (string a, string b)
4037 // bool operator == (string a, string b)
4039 // bool operator != (Delegate a, Delegate b)
4040 // bool operator == (Delegate a, Delegate b)
4042 // bool operator != (bool a, bool b)
4043 // bool operator == (bool a, bool b)
4045 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4046 // they implement an implicit conversion to any of types above. This does
4047 // not apply when both operands are of same reference type
4049 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4050 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4055 // Now try lifted version of predefined operators
4057 if (no_arg_conv && !l.IsNullableType) {
4059 // Optimizes cases which won't match
4062 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4068 // The == and != operators permit one operand to be a value of a nullable
4069 // type and the other to be the null literal, even if no predefined or user-defined
4070 // operator (in unlifted or lifted form) exists for the operation.
4072 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4073 var lifted = new Nullable.LiftedBinaryOperator (this);
4075 lifted.Right = right;
4076 return lifted.Resolve (ec);
4081 // bool operator != (object a, object b)
4082 // bool operator == (object a, object b)
4084 // An explicit reference conversion exists from the
4085 // type of either operand to the type of the other operand.
4088 // Optimize common path
4090 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4093 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4094 !Convert.ExplicitReferenceConversionExists (r, l))
4097 // Reject allowed explicit conversions like int->object
4098 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4101 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4102 ec.Report.Warning (253, 2, loc,
4103 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4104 l.GetSignatureForError ());
4106 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4107 ec.Report.Warning (252, 2, loc,
4108 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4109 r.GetSignatureForError ());
4115 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4118 // bool operator == (void* x, void* y);
4119 // bool operator != (void* x, void* y);
4120 // bool operator < (void* x, void* y);
4121 // bool operator > (void* x, void* y);
4122 // bool operator <= (void* x, void* y);
4123 // bool operator >= (void* x, void* y);
4125 if ((oper & Operator.ComparisonMask) != 0) {
4128 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4135 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4141 type = ec.BuiltinTypes.Bool;
4145 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4149 // Build-in operators method overloading
4151 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4153 PredefinedOperator best_operator = null;
4154 TypeSpec l = left.Type;
4155 TypeSpec r = right.Type;
4156 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4158 foreach (PredefinedOperator po in operators) {
4159 if ((po.OperatorsMask & oper_mask) == 0)
4162 if (primitives_only) {
4163 if (!po.IsPrimitiveApplicable (l, r))
4166 if (!po.IsApplicable (ec, left, right))
4170 if (best_operator == null) {
4172 if (primitives_only)
4178 best_operator = po.ResolveBetterOperator (ec, best_operator);
4180 if (best_operator == null) {
4181 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4182 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4189 if (best_operator == null)
4192 return best_operator.ConvertResult (ec, this);
4196 // Optimize & constant expressions with 0 value
4198 Expression OptimizeAndOperation (Expression expr)
4200 Constant rc = right as Constant;
4201 Constant lc = left as Constant;
4202 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4204 // The result is a constant with side-effect
4206 Constant side_effect = rc == null ?
4207 new SideEffectConstant (lc, right, loc) :
4208 new SideEffectConstant (rc, left, loc);
4210 return ReducedExpression.Create (side_effect, expr);
4217 // Value types can be compared with the null literal because of the lifting
4218 // language rules. However the result is always true or false.
4220 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4222 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4223 type = rc.BuiltinTypes.Bool;
4227 // FIXME: Handle side effect constants
4228 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4230 if ((Oper & Operator.EqualityMask) != 0) {
4231 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4232 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4234 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4235 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4242 // Performs user-operator overloading
4244 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4246 Expression oper_expr;
4248 var op = ConvertBinaryToUserOperator (oper);
4250 if (l.IsNullableType)
4251 l = Nullable.NullableInfo.GetUnderlyingType (l);
4253 if (r.IsNullableType)
4254 r = Nullable.NullableInfo.GetUnderlyingType (r);
4256 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4257 IList<MemberSpec> right_operators = null;
4260 right_operators = MemberCache.GetUserOperator (r, op, false);
4261 if (right_operators == null && left_operators == null)
4263 } else if (left_operators == null) {
4267 Arguments args = new Arguments (2);
4268 Argument larg = new Argument (left);
4270 Argument rarg = new Argument (right);
4274 // User-defined operator implementations always take precedence
4275 // over predefined operator implementations
4277 if (left_operators != null && right_operators != null) {
4278 left_operators = CombineUserOperators (left_operators, right_operators);
4279 } else if (right_operators != null) {
4280 left_operators = right_operators;
4283 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4284 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4286 var res = new OverloadResolver (left_operators, restr, loc);
4288 var oper_method = res.ResolveOperator (rc, ref args);
4289 if (oper_method == null) {
4291 // Logical && and || cannot be lifted
4293 if ((oper & Operator.LogicalMask) != 0)
4297 // Apply lifted user operators only for liftable types. Implicit conversion
4298 // to nullable types is not allowed
4300 if (!IsLiftedOperatorApplicable ())
4303 // TODO: Cache the result in module container
4304 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4305 if (lifted_methods == null)
4308 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4310 oper_method = res.ResolveOperator (rc, ref args);
4311 if (oper_method == null)
4314 MethodSpec best_original = null;
4315 foreach (MethodSpec ms in left_operators) {
4316 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4322 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4324 // Expression trees use lifted notation in this case
4326 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4327 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4330 var ptypes = best_original.Parameters.Types;
4332 if (left.IsNull || right.IsNull) {
4334 // The lifted operator produces the value false if one or both operands are null for
4335 // relational operators.
4337 if ((oper & Operator.ComparisonMask) != 0) {
4339 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4340 // because return type is actually bool
4342 // For some reason CSC does not report this warning for equality operators
4344 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4347 // The lifted operator produces a null value if one or both operands are null
4349 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4350 type = oper_method.ReturnType;
4351 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4355 type = oper_method.ReturnType;
4356 var lifted = new Nullable.LiftedBinaryOperator (this);
4357 lifted.UserOperator = best_original;
4359 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4360 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4363 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4364 lifted.UnwrapRight = new Nullable.Unwrap (right);
4367 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4368 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4370 return lifted.Resolve (rc);
4373 if ((oper & Operator.LogicalMask) != 0) {
4374 // TODO: CreateExpressionTree is allocated every time
4375 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4376 oper == Operator.LogicalAnd, loc).Resolve (rc);
4378 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4381 this.left = larg.Expr;
4382 this.right = rarg.Expr;
4387 bool IsLiftedOperatorApplicable ()
4389 if (left.Type.IsNullableType) {
4390 if ((oper & Operator.EqualityMask) != 0)
4391 return !right.IsNull;
4396 if (right.Type.IsNullableType) {
4397 if ((oper & Operator.EqualityMask) != 0)
4398 return !left.IsNull;
4403 if (TypeSpec.IsValueType (left.Type))
4404 return right.IsNull;
4406 if (TypeSpec.IsValueType (right.Type))
4412 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4414 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4415 if (nullable_type == null)
4419 // Lifted operators permit predefined and user-defined operators that operate
4420 // on non-nullable value types to also be used with nullable forms of those types.
4421 // Lifted operators are constructed from predefined and user-defined operators
4422 // that meet certain requirements
4424 List<MemberSpec> lifted = null;
4425 foreach (MethodSpec oper in operators) {
4427 if ((Oper & Operator.ComparisonMask) != 0) {
4429 // Result type must be of type bool for lifted comparison operators
4431 rt = oper.ReturnType;
4432 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4435 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4441 var ptypes = oper.Parameters.Types;
4442 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4446 // LAMESPEC: I am not sure why but for equality operators to be lifted
4447 // both types have to match
4449 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4453 lifted = new List<MemberSpec> ();
4456 // The lifted form is constructed by adding a single ? modifier to each operand and
4457 // result type except for comparison operators where return type is bool
4460 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4462 var parameters = ParametersCompiled.CreateFullyResolved (
4463 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4464 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4466 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4467 rt, parameters, oper.Modifiers);
4469 lifted.Add (lifted_op);
4476 // Merge two sets of user operators into one, they are mostly distinguish
4477 // except when they share base type and it contains an operator
4479 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4481 var combined = new List<MemberSpec> (left.Count + right.Count);
4482 combined.AddRange (left);
4483 foreach (var r in right) {
4485 foreach (var l in left) {
4486 if (l.DeclaringType == r.DeclaringType) {
4499 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4501 if (c is IntegralConstant || c is CharConstant) {
4503 c.ConvertExplicitly (true, type);
4504 } catch (OverflowException) {
4505 ec.Report.Warning (652, 2, loc,
4506 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4507 type.GetSignatureForError ());
4513 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4514 /// context of a conditional bool expression. This function will return
4515 /// false if it is was possible to use EmitBranchable, or true if it was.
4517 /// The expression's code is generated, and we will generate a branch to `target'
4518 /// if the resulting expression value is equal to isTrue
4520 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4522 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4523 left = left.EmitToField (ec);
4525 if ((oper & Operator.LogicalMask) == 0) {
4526 right = right.EmitToField (ec);
4531 // This is more complicated than it looks, but its just to avoid
4532 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4533 // but on top of that we want for == and != to use a special path
4534 // if we are comparing against null
4536 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4537 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4540 // put the constant on the rhs, for simplicity
4542 if (left is Constant) {
4543 Expression swap = right;
4549 // brtrue/brfalse works with native int only
4551 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4552 left.EmitBranchable (ec, target, my_on_true);
4555 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4556 // right is a boolean, and it's not 'false' => it is 'true'
4557 left.EmitBranchable (ec, target, !my_on_true);
4561 } else if (oper == Operator.LogicalAnd) {
4564 Label tests_end = ec.DefineLabel ();
4566 left.EmitBranchable (ec, tests_end, false);
4567 right.EmitBranchable (ec, target, true);
4568 ec.MarkLabel (tests_end);
4571 // This optimizes code like this
4572 // if (true && i > 4)
4574 if (!(left is Constant))
4575 left.EmitBranchable (ec, target, false);
4577 if (!(right is Constant))
4578 right.EmitBranchable (ec, target, false);
4583 } else if (oper == Operator.LogicalOr){
4585 left.EmitBranchable (ec, target, true);
4586 right.EmitBranchable (ec, target, true);
4589 Label tests_end = ec.DefineLabel ();
4590 left.EmitBranchable (ec, tests_end, true);
4591 right.EmitBranchable (ec, target, false);
4592 ec.MarkLabel (tests_end);
4597 } else if ((oper & Operator.ComparisonMask) == 0) {
4598 base.EmitBranchable (ec, target, on_true);
4605 TypeSpec t = left.Type;
4606 bool is_float = IsFloat (t);
4607 bool is_unsigned = is_float || IsUnsigned (t);
4610 case Operator.Equality:
4612 ec.Emit (OpCodes.Beq, target);
4614 ec.Emit (OpCodes.Bne_Un, target);
4617 case Operator.Inequality:
4619 ec.Emit (OpCodes.Bne_Un, target);
4621 ec.Emit (OpCodes.Beq, target);
4624 case Operator.LessThan:
4626 if (is_unsigned && !is_float)
4627 ec.Emit (OpCodes.Blt_Un, target);
4629 ec.Emit (OpCodes.Blt, target);
4632 ec.Emit (OpCodes.Bge_Un, target);
4634 ec.Emit (OpCodes.Bge, target);
4637 case Operator.GreaterThan:
4639 if (is_unsigned && !is_float)
4640 ec.Emit (OpCodes.Bgt_Un, target);
4642 ec.Emit (OpCodes.Bgt, target);
4645 ec.Emit (OpCodes.Ble_Un, target);
4647 ec.Emit (OpCodes.Ble, target);
4650 case Operator.LessThanOrEqual:
4652 if (is_unsigned && !is_float)
4653 ec.Emit (OpCodes.Ble_Un, target);
4655 ec.Emit (OpCodes.Ble, target);
4658 ec.Emit (OpCodes.Bgt_Un, target);
4660 ec.Emit (OpCodes.Bgt, target);
4664 case Operator.GreaterThanOrEqual:
4666 if (is_unsigned && !is_float)
4667 ec.Emit (OpCodes.Bge_Un, target);
4669 ec.Emit (OpCodes.Bge, target);
4672 ec.Emit (OpCodes.Blt_Un, target);
4674 ec.Emit (OpCodes.Blt, target);
4677 throw new InternalErrorException (oper.ToString ());
4681 public override void Emit (EmitContext ec)
4683 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4684 left = left.EmitToField (ec);
4686 if ((oper & Operator.LogicalMask) == 0) {
4687 right = right.EmitToField (ec);
4692 // Handle short-circuit operators differently
4695 if ((oper & Operator.LogicalMask) != 0) {
4696 Label load_result = ec.DefineLabel ();
4697 Label end = ec.DefineLabel ();
4699 bool is_or = oper == Operator.LogicalOr;
4700 left.EmitBranchable (ec, load_result, is_or);
4702 ec.Emit (OpCodes.Br_S, end);
4704 ec.MarkLabel (load_result);
4705 ec.EmitInt (is_or ? 1 : 0);
4711 // Optimize zero-based operations which cannot be optimized at expression level
4713 if (oper == Operator.Subtraction) {
4714 var lc = left as IntegralConstant;
4715 if (lc != null && lc.IsDefaultValue) {
4717 ec.Emit (OpCodes.Neg);
4722 EmitOperator (ec, left, right);
4725 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4730 EmitOperatorOpcode (ec, oper, left.Type, right);
4733 // Emit result enumerable conversion this way because it's quite complicated get it
4734 // to resolved tree because expression tree cannot see it.
4736 if (enum_conversion != 0)
4737 ConvCast.Emit (ec, enum_conversion);
4740 public override void EmitSideEffect (EmitContext ec)
4742 if ((oper & Operator.LogicalMask) != 0 ||
4743 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4744 base.EmitSideEffect (ec);
4746 left.EmitSideEffect (ec);
4747 right.EmitSideEffect (ec);
4751 public override Expression EmitToField (EmitContext ec)
4753 if ((oper & Operator.LogicalMask) == 0) {
4754 var await_expr = left as Await;
4755 if (await_expr != null && right.IsSideEffectFree) {
4756 await_expr.Statement.EmitPrologue (ec);
4757 left = await_expr.Statement.GetResultExpression (ec);
4761 await_expr = right as Await;
4762 if (await_expr != null && left.IsSideEffectFree) {
4763 await_expr.Statement.EmitPrologue (ec);
4764 right = await_expr.Statement.GetResultExpression (ec);
4769 return base.EmitToField (ec);
4772 protected override void CloneTo (CloneContext clonectx, Expression t)
4774 Binary target = (Binary) t;
4776 target.left = left.Clone (clonectx);
4777 target.right = right.Clone (clonectx);
4780 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4782 Arguments binder_args = new Arguments (4);
4784 MemberAccess sle = new MemberAccess (new MemberAccess (
4785 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4787 CSharpBinderFlags flags = 0;
4788 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4789 flags = CSharpBinderFlags.CheckedContext;
4791 if ((oper & Operator.LogicalMask) != 0)
4792 flags |= CSharpBinderFlags.BinaryOperationLogical;
4794 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4795 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4796 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4797 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4799 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4802 public override Expression CreateExpressionTree (ResolveContext ec)
4804 return CreateExpressionTree (ec, null);
4807 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4810 bool lift_arg = false;
4813 case Operator.Addition:
4814 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4815 method_name = "AddChecked";
4817 method_name = "Add";
4819 case Operator.BitwiseAnd:
4820 method_name = "And";
4822 case Operator.BitwiseOr:
4825 case Operator.Division:
4826 method_name = "Divide";
4828 case Operator.Equality:
4829 method_name = "Equal";
4832 case Operator.ExclusiveOr:
4833 method_name = "ExclusiveOr";
4835 case Operator.GreaterThan:
4836 method_name = "GreaterThan";
4839 case Operator.GreaterThanOrEqual:
4840 method_name = "GreaterThanOrEqual";
4843 case Operator.Inequality:
4844 method_name = "NotEqual";
4847 case Operator.LeftShift:
4848 method_name = "LeftShift";
4850 case Operator.LessThan:
4851 method_name = "LessThan";
4854 case Operator.LessThanOrEqual:
4855 method_name = "LessThanOrEqual";
4858 case Operator.LogicalAnd:
4859 method_name = "AndAlso";
4861 case Operator.LogicalOr:
4862 method_name = "OrElse";
4864 case Operator.Modulus:
4865 method_name = "Modulo";
4867 case Operator.Multiply:
4868 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4869 method_name = "MultiplyChecked";
4871 method_name = "Multiply";
4873 case Operator.RightShift:
4874 method_name = "RightShift";
4876 case Operator.Subtraction:
4877 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4878 method_name = "SubtractChecked";
4880 method_name = "Subtract";
4884 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4887 Arguments args = new Arguments (2);
4888 args.Add (new Argument (left.CreateExpressionTree (ec)));
4889 args.Add (new Argument (right.CreateExpressionTree (ec)));
4890 if (method != null) {
4892 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4894 args.Add (new Argument (method));
4897 return CreateExpressionFactoryCall (ec, method_name, args);
4900 public override object Accept (StructuralVisitor visitor)
4902 return visitor.Visit (this);
4908 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4909 // b, c, d... may be strings or objects.
4911 public class StringConcat : Expression
4913 Arguments arguments;
4915 StringConcat (Location loc)
4918 arguments = new Arguments (2);
4921 public override bool ContainsEmitWithAwait ()
4923 return arguments.ContainsEmitWithAwait ();
4926 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4928 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4929 throw new ArgumentException ();
4931 var s = new StringConcat (loc);
4932 s.type = rc.BuiltinTypes.String;
4933 s.eclass = ExprClass.Value;
4935 s.Append (rc, left);
4936 s.Append (rc, right);
4940 public override Expression CreateExpressionTree (ResolveContext ec)
4942 Argument arg = arguments [0];
4943 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4947 // Creates nested calls tree from an array of arguments used for IL emit
4949 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4951 Arguments concat_args = new Arguments (2);
4952 Arguments add_args = new Arguments (3);
4954 concat_args.Add (left);
4955 add_args.Add (new Argument (left_etree));
4957 concat_args.Add (arguments [pos]);
4958 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4960 var methods = GetConcatMethodCandidates ();
4961 if (methods == null)
4964 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4965 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4969 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4971 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4972 if (++pos == arguments.Count)
4975 left = new Argument (new EmptyExpression (method.ReturnType));
4976 return CreateExpressionAddCall (ec, left, expr, pos);
4979 protected override Expression DoResolve (ResolveContext ec)
4984 void Append (ResolveContext rc, Expression operand)
4989 StringConstant sc = operand as StringConstant;
4991 if (arguments.Count != 0) {
4992 Argument last_argument = arguments [arguments.Count - 1];
4993 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4994 if (last_expr_constant != null) {
4995 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5001 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5003 StringConcat concat_oper = operand as StringConcat;
5004 if (concat_oper != null) {
5005 arguments.AddRange (concat_oper.arguments);
5010 arguments.Add (new Argument (operand));
5013 IList<MemberSpec> GetConcatMethodCandidates ()
5015 return MemberCache.FindMembers (type, "Concat", true);
5018 public override void Emit (EmitContext ec)
5020 // Optimize by removing any extra null arguments, they are no-op
5021 for (int i = 0; i < arguments.Count; ++i) {
5022 if (arguments[i].Expr is NullConstant)
5023 arguments.RemoveAt (i--);
5026 var members = GetConcatMethodCandidates ();
5027 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5028 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5029 if (method != null) {
5030 var call = new CallEmitter ();
5031 call.EmitPredefined (ec, method, arguments);
5035 public override void FlowAnalysis (FlowAnalysisContext fc)
5037 arguments.FlowAnalysis (fc);
5040 public override SLE.Expression MakeExpression (BuilderContext ctx)
5042 if (arguments.Count != 2)
5043 throw new NotImplementedException ("arguments.Count != 2");
5045 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5046 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5051 // User-defined conditional logical operator
5053 public class ConditionalLogicalOperator : UserOperatorCall
5055 readonly bool is_and;
5056 Expression oper_expr;
5058 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5059 : base (oper, arguments, expr_tree, loc)
5061 this.is_and = is_and;
5062 eclass = ExprClass.Unresolved;
5065 protected override Expression DoResolve (ResolveContext ec)
5067 AParametersCollection pd = oper.Parameters;
5068 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5069 ec.Report.Error (217, loc,
5070 "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",
5071 oper.GetSignatureForError ());
5075 Expression left_dup = new EmptyExpression (type);
5076 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5077 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5078 if (op_true == null || op_false == null) {
5079 ec.Report.Error (218, loc,
5080 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5081 type.GetSignatureForError (), oper.GetSignatureForError ());
5085 oper_expr = is_and ? op_false : op_true;
5086 eclass = ExprClass.Value;
5090 public override void Emit (EmitContext ec)
5092 Label end_target = ec.DefineLabel ();
5095 // Emit and duplicate left argument
5097 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5098 if (right_contains_await) {
5099 arguments[0] = arguments[0].EmitToField (ec, false);
5100 arguments[0].Expr.Emit (ec);
5102 arguments[0].Expr.Emit (ec);
5103 ec.Emit (OpCodes.Dup);
5104 arguments.RemoveAt (0);
5107 oper_expr.EmitBranchable (ec, end_target, true);
5111 if (right_contains_await) {
5113 // Special handling when right expression contains await and left argument
5114 // could not be left on stack before logical branch
5116 Label skip_left_load = ec.DefineLabel ();
5117 ec.Emit (OpCodes.Br_S, skip_left_load);
5118 ec.MarkLabel (end_target);
5119 arguments[0].Expr.Emit (ec);
5120 ec.MarkLabel (skip_left_load);
5122 ec.MarkLabel (end_target);
5127 public class PointerArithmetic : Expression {
5128 Expression left, right;
5129 readonly Binary.Operator op;
5132 // We assume that `l' is always a pointer
5134 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5143 public override bool ContainsEmitWithAwait ()
5145 throw new NotImplementedException ();
5148 public override Expression CreateExpressionTree (ResolveContext ec)
5150 Error_PointerInsideExpressionTree (ec);
5154 protected override Expression DoResolve (ResolveContext ec)
5156 eclass = ExprClass.Variable;
5158 var pc = left.Type as PointerContainer;
5159 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5160 Error_VoidPointerOperation (ec);
5167 public override void Emit (EmitContext ec)
5169 TypeSpec op_type = left.Type;
5171 // It must be either array or fixed buffer
5173 if (TypeManager.HasElementType (op_type)) {
5174 element = TypeManager.GetElementType (op_type);
5176 FieldExpr fe = left as FieldExpr;
5178 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5183 int size = BuiltinTypeSpec.GetSize(element);
5184 TypeSpec rtype = right.Type;
5186 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5188 // handle (pointer - pointer)
5192 ec.Emit (OpCodes.Sub);
5196 ec.Emit (OpCodes.Sizeof, element);
5199 ec.Emit (OpCodes.Div);
5201 ec.Emit (OpCodes.Conv_I8);
5204 // handle + and - on (pointer op int)
5206 Constant left_const = left as Constant;
5207 if (left_const != null) {
5209 // Optimize ((T*)null) pointer operations
5211 if (left_const.IsDefaultValue) {
5212 left = EmptyExpression.Null;
5220 var right_const = right as Constant;
5221 if (right_const != null) {
5223 // Optimize 0-based arithmetic
5225 if (right_const.IsDefaultValue)
5229 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5231 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5233 // TODO: Should be the checks resolve context sensitive?
5234 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5235 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5241 switch (rtype.BuiltinType) {
5242 case BuiltinTypeSpec.Type.SByte:
5243 case BuiltinTypeSpec.Type.Byte:
5244 case BuiltinTypeSpec.Type.Short:
5245 case BuiltinTypeSpec.Type.UShort:
5246 ec.Emit (OpCodes.Conv_I);
5248 case BuiltinTypeSpec.Type.UInt:
5249 ec.Emit (OpCodes.Conv_U);
5253 if (right_const == null && size != 1){
5255 ec.Emit (OpCodes.Sizeof, element);
5258 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5259 ec.Emit (OpCodes.Conv_I8);
5261 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5264 if (left_const == null) {
5265 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5266 ec.Emit (OpCodes.Conv_I);
5267 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5268 ec.Emit (OpCodes.Conv_U);
5270 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5277 // A boolean-expression is an expression that yields a result
5280 public class BooleanExpression : ShimExpression
5282 public BooleanExpression (Expression expr)
5285 this.loc = expr.Location;
5288 public override Expression CreateExpressionTree (ResolveContext ec)
5290 // TODO: We should emit IsTrue (v4) instead of direct user operator
5291 // call but that would break csc compatibility
5292 return base.CreateExpressionTree (ec);
5295 protected override Expression DoResolve (ResolveContext ec)
5297 // A boolean-expression is required to be of a type
5298 // that can be implicitly converted to bool or of
5299 // a type that implements operator true
5301 expr = expr.Resolve (ec);
5305 Assign ass = expr as Assign;
5306 if (ass != null && ass.Source is Constant) {
5307 ec.Report.Warning (665, 3, loc,
5308 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5311 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5314 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5315 Arguments args = new Arguments (1);
5316 args.Add (new Argument (expr));
5317 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5320 type = ec.BuiltinTypes.Bool;
5321 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5322 if (converted != null)
5326 // If no implicit conversion to bool exists, try using `operator true'
5328 converted = GetOperatorTrue (ec, expr, loc);
5329 if (converted == null) {
5330 expr.Error_ValueCannotBeConverted (ec, type, false);
5337 public override object Accept (StructuralVisitor visitor)
5339 return visitor.Visit (this);
5343 public class BooleanExpressionFalse : Unary
5345 public BooleanExpressionFalse (Expression expr)
5346 : base (Operator.LogicalNot, expr, expr.Location)
5350 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5352 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5357 /// Implements the ternary conditional operator (?:)
5359 public class Conditional : Expression {
5360 Expression expr, true_expr, false_expr;
5362 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5365 this.true_expr = true_expr;
5366 this.false_expr = false_expr;
5372 public Expression Expr {
5378 public Expression TrueExpr {
5384 public Expression FalseExpr {
5392 public override bool ContainsEmitWithAwait ()
5394 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5397 public override Expression CreateExpressionTree (ResolveContext ec)
5399 Arguments args = new Arguments (3);
5400 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5401 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5402 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5403 return CreateExpressionFactoryCall (ec, "Condition", args);
5406 protected override Expression DoResolve (ResolveContext ec)
5408 expr = expr.Resolve (ec);
5409 true_expr = true_expr.Resolve (ec);
5410 false_expr = false_expr.Resolve (ec);
5412 if (true_expr == null || false_expr == null || expr == null)
5415 eclass = ExprClass.Value;
5416 TypeSpec true_type = true_expr.Type;
5417 TypeSpec false_type = false_expr.Type;
5421 // First, if an implicit conversion exists from true_expr
5422 // to false_expr, then the result type is of type false_expr.Type
5424 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5425 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5426 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5428 // Check if both can convert implicitly to each other's type
5432 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5433 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5435 // LAMESPEC: There seems to be hardcoded promotition to int type when
5436 // both sides are numeric constants and one side is int constant and
5437 // other side is numeric constant convertible to int.
5439 // var res = condition ? (short)1 : 1;
5441 // Type of res is int even if according to the spec the conversion is
5442 // ambiguous because 1 literal can be converted to short.
5444 if (conv_false_expr != null) {
5445 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5447 conv_false_expr = null;
5448 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5449 conv_false_expr = null;
5453 if (conv_false_expr != null) {
5454 ec.Report.Error (172, true_expr.Location,
5455 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5456 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5461 if (true_expr.Type != type)
5462 true_expr = EmptyCast.Create (true_expr, type);
5463 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5466 ec.Report.Error (173, true_expr.Location,
5467 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5468 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5473 Constant c = expr as Constant;
5475 bool is_false = c.IsDefaultValue;
5478 // Don't issue the warning for constant expressions
5480 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5481 // CSC: Missing warning
5482 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
5485 return ReducedExpression.Create (
5486 is_false ? false_expr : true_expr, this,
5487 false_expr is Constant && true_expr is Constant).Resolve (ec);
5493 public override void Emit (EmitContext ec)
5495 Label false_target = ec.DefineLabel ();
5496 Label end_target = ec.DefineLabel ();
5498 expr.EmitBranchable (ec, false_target, false);
5499 true_expr.Emit (ec);
5502 // Verifier doesn't support interface merging. When there are two types on
5503 // the stack without common type hint and the common type is an interface.
5504 // Use temporary local to give verifier hint on what type to unify the stack
5506 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5507 var temp = ec.GetTemporaryLocal (type);
5508 ec.Emit (OpCodes.Stloc, temp);
5509 ec.Emit (OpCodes.Ldloc, temp);
5510 ec.FreeTemporaryLocal (temp, type);
5513 ec.Emit (OpCodes.Br, end_target);
5514 ec.MarkLabel (false_target);
5515 false_expr.Emit (ec);
5516 ec.MarkLabel (end_target);
5519 public override void FlowAnalysis (FlowAnalysisContext fc)
5521 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5523 expr.FlowAnalysis (fc);
5524 var da_true = fc.DefiniteAssignmentOnTrue;
5525 var da_false = fc.DefiniteAssignmentOnFalse;
5527 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_true);
5528 true_expr.FlowAnalysis (fc);
5529 var true_fc = fc.DefiniteAssignment;
5531 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_false);
5532 false_expr.FlowAnalysis (fc);
5534 fc.DefiniteAssignment &= true_fc;
5535 if (fc.DefiniteAssignmentOnTrue != null)
5536 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
5537 if (fc.DefiniteAssignmentOnFalse != null)
5538 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5541 protected override void CloneTo (CloneContext clonectx, Expression t)
5543 Conditional target = (Conditional) t;
5545 target.expr = expr.Clone (clonectx);
5546 target.true_expr = true_expr.Clone (clonectx);
5547 target.false_expr = false_expr.Clone (clonectx);
5551 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5553 LocalTemporary temp;
5556 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5557 public abstract void SetHasAddressTaken ();
5559 public abstract bool IsLockedByStatement { get; set; }
5561 public abstract bool IsFixed { get; }
5562 public abstract bool IsRef { get; }
5563 public abstract string Name { get; }
5566 // Variable IL data, it has to be protected to encapsulate hoisted variables
5568 protected abstract ILocalVariable Variable { get; }
5571 // Variable flow-analysis data
5573 public abstract VariableInfo VariableInfo { get; }
5576 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5578 HoistedVariable hv = GetHoistedVariable (ec);
5580 hv.AddressOf (ec, mode);
5584 Variable.EmitAddressOf (ec);
5587 public override bool ContainsEmitWithAwait ()
5592 public override Expression CreateExpressionTree (ResolveContext ec)
5594 HoistedVariable hv = GetHoistedVariable (ec);
5596 return hv.CreateExpressionTree ();
5598 Arguments arg = new Arguments (1);
5599 arg.Add (new Argument (this));
5600 return CreateExpressionFactoryCall (ec, "Constant", arg);
5603 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5605 if (IsLockedByStatement) {
5606 rc.Report.Warning (728, 2, loc,
5607 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5614 public override void Emit (EmitContext ec)
5619 public override void EmitSideEffect (EmitContext ec)
5625 // This method is used by parameters that are references, that are
5626 // being passed as references: we only want to pass the pointer (that
5627 // is already stored in the parameter, not the address of the pointer,
5628 // and not the value of the variable).
5630 public void EmitLoad (EmitContext ec)
5635 public void Emit (EmitContext ec, bool leave_copy)
5637 HoistedVariable hv = GetHoistedVariable (ec);
5639 hv.Emit (ec, leave_copy);
5647 // If we are a reference, we loaded on the stack a pointer
5648 // Now lets load the real value
5650 ec.EmitLoadFromPtr (type);
5654 ec.Emit (OpCodes.Dup);
5657 temp = new LocalTemporary (Type);
5663 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5664 bool prepare_for_load)
5666 HoistedVariable hv = GetHoistedVariable (ec);
5668 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5672 New n_source = source as New;
5673 if (n_source != null) {
5674 if (!n_source.Emit (ec, this)) {
5678 ec.EmitLoadFromPtr (type);
5690 ec.Emit (OpCodes.Dup);
5692 temp = new LocalTemporary (Type);
5698 ec.EmitStoreFromPtr (type);
5700 Variable.EmitAssign (ec);
5708 public override Expression EmitToField (EmitContext ec)
5710 HoistedVariable hv = GetHoistedVariable (ec);
5712 return hv.EmitToField (ec);
5715 return base.EmitToField (ec);
5718 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5720 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5723 public HoistedVariable GetHoistedVariable (EmitContext ec)
5725 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5728 public override string GetSignatureForError ()
5733 public bool IsHoisted {
5734 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5739 // Resolved reference to a local variable
5741 public class LocalVariableReference : VariableReference
5743 public LocalVariable local_info;
5745 public LocalVariableReference (LocalVariable li, Location l)
5747 this.local_info = li;
5751 public override VariableInfo VariableInfo {
5752 get { return local_info.VariableInfo; }
5755 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5757 return local_info.HoistedVariant;
5763 // A local variable is always fixed
5765 public override bool IsFixed {
5771 public override bool IsLockedByStatement {
5773 return local_info.IsLocked;
5776 local_info.IsLocked = value;
5780 public override bool IsRef {
5781 get { return false; }
5784 public override string Name {
5785 get { return local_info.Name; }
5790 public override void FlowAnalysis (FlowAnalysisContext fc)
5792 VariableInfo variable_info = VariableInfo;
5793 if (variable_info == null)
5796 if (fc.IsDefinitelyAssigned (variable_info))
5799 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5800 variable_info.SetAssigned (fc.DefiniteAssignment, true);
5803 public override void SetHasAddressTaken ()
5805 local_info.SetHasAddressTaken ();
5808 void DoResolveBase (ResolveContext ec)
5811 // If we are referencing a variable from the external block
5812 // flag it for capturing
5814 if (ec.MustCaptureVariable (local_info)) {
5815 if (local_info.AddressTaken) {
5816 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5817 } else if (local_info.IsFixed) {
5818 ec.Report.Error (1764, loc,
5819 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5820 GetSignatureForError ());
5823 if (ec.IsVariableCapturingRequired) {
5824 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5825 storey.CaptureLocalVariable (ec, local_info);
5829 eclass = ExprClass.Variable;
5830 type = local_info.Type;
5833 protected override Expression DoResolve (ResolveContext ec)
5835 local_info.SetIsUsed ();
5841 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5844 // Don't be too pedantic when variable is used as out param or for some broken code
5845 // which uses property/indexer access to run some initialization
5847 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5848 local_info.SetIsUsed ();
5850 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5851 if (rhs == EmptyExpression.LValueMemberAccess) {
5852 // CS1654 already reported
5856 if (rhs == EmptyExpression.OutAccess) {
5857 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5858 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5859 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5860 } else if (rhs == EmptyExpression.UnaryAddress) {
5861 code = 459; msg = "Cannot take the address of {1} `{0}'";
5863 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5865 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5869 if (eclass == ExprClass.Unresolved)
5872 return base.DoResolveLValue (ec, rhs);
5875 public override int GetHashCode ()
5877 return local_info.GetHashCode ();
5880 public override bool Equals (object obj)
5882 LocalVariableReference lvr = obj as LocalVariableReference;
5886 return local_info == lvr.local_info;
5889 protected override ILocalVariable Variable {
5890 get { return local_info; }
5893 public override string ToString ()
5895 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5898 protected override void CloneTo (CloneContext clonectx, Expression t)
5905 /// This represents a reference to a parameter in the intermediate
5908 public class ParameterReference : VariableReference
5910 protected ParametersBlock.ParameterInfo pi;
5912 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5920 public override bool IsLockedByStatement {
5925 pi.IsLocked = value;
5929 public override bool IsRef {
5930 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5933 bool HasOutModifier {
5934 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5937 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5939 return pi.Parameter.HoistedVariant;
5943 // A ref or out parameter is classified as a moveable variable, even
5944 // if the argument given for the parameter is a fixed variable
5946 public override bool IsFixed {
5947 get { return !IsRef; }
5950 public override string Name {
5951 get { return Parameter.Name; }
5954 public Parameter Parameter {
5955 get { return pi.Parameter; }
5958 public override VariableInfo VariableInfo {
5959 get { return pi.VariableInfo; }
5962 protected override ILocalVariable Variable {
5963 get { return Parameter; }
5968 public override void AddressOf (EmitContext ec, AddressOp mode)
5971 // ParameterReferences might already be a reference
5978 base.AddressOf (ec, mode);
5981 public override void SetHasAddressTaken ()
5983 Parameter.HasAddressTaken = true;
5986 bool DoResolveBase (ResolveContext ec)
5988 if (eclass != ExprClass.Unresolved)
5991 type = pi.ParameterType;
5992 eclass = ExprClass.Variable;
5995 // If we are referencing a parameter from the external block
5996 // flag it for capturing
5998 if (ec.MustCaptureVariable (pi)) {
5999 if (Parameter.HasAddressTaken)
6000 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6003 ec.Report.Error (1628, loc,
6004 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6005 Name, ec.CurrentAnonymousMethod.ContainerType);
6008 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6009 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6010 storey.CaptureParameter (ec, pi, this);
6017 public override int GetHashCode ()
6019 return Name.GetHashCode ();
6022 public override bool Equals (object obj)
6024 ParameterReference pr = obj as ParameterReference;
6028 return Name == pr.Name;
6031 protected override void CloneTo (CloneContext clonectx, Expression target)
6037 public override Expression CreateExpressionTree (ResolveContext ec)
6039 HoistedVariable hv = GetHoistedVariable (ec);
6041 return hv.CreateExpressionTree ();
6043 return Parameter.ExpressionTreeVariableReference ();
6046 protected override Expression DoResolve (ResolveContext ec)
6048 if (!DoResolveBase (ec))
6054 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6056 if (!DoResolveBase (ec))
6059 if (Parameter.HoistedVariant != null)
6060 Parameter.HoistedVariant.IsAssigned = true;
6062 return base.DoResolveLValue (ec, right_side);
6065 public override void FlowAnalysis (FlowAnalysisContext fc)
6067 VariableInfo variable_info = VariableInfo;
6068 if (variable_info == null)
6071 if (fc.IsDefinitelyAssigned (variable_info))
6074 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6075 fc.SetVariableAssigned (variable_info);
6080 /// Invocation of methods or delegates.
6082 public class Invocation : ExpressionStatement
6084 protected Arguments arguments;
6085 protected Expression expr;
6086 protected MethodGroupExpr mg;
6088 public Invocation (Expression expr, Arguments arguments)
6091 this.arguments = arguments;
6093 loc = expr.Location;
6098 public Arguments Arguments {
6104 public Expression Exp {
6110 public MethodGroupExpr MethodGroup {
6116 public override Location StartLocation {
6118 return expr.StartLocation;
6124 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6126 if (MethodGroup == null)
6129 var candidate = MethodGroup.BestCandidate;
6130 if (candidate == null || !(candidate.IsStatic || Exp is This))
6133 var args_count = arguments == null ? 0 : arguments.Count;
6134 if (args_count != body.Parameters.Count)
6137 var lambda_parameters = body.Block.Parameters.FixedParameters;
6138 for (int i = 0; i < args_count; ++i) {
6139 var pr = arguments[i].Expr as ParameterReference;
6143 if (lambda_parameters[i] != pr.Parameter)
6146 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6150 var emg = MethodGroup as ExtensionMethodGroupExpr;
6152 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6153 if (candidate.IsGeneric) {
6154 var targs = new TypeExpression [candidate.Arity];
6155 for (int i = 0; i < targs.Length; ++i) {
6156 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6159 mg.SetTypeArguments (null, new TypeArguments (targs));
6168 protected override void CloneTo (CloneContext clonectx, Expression t)
6170 Invocation target = (Invocation) t;
6172 if (arguments != null)
6173 target.arguments = arguments.Clone (clonectx);
6175 target.expr = expr.Clone (clonectx);
6178 public override bool ContainsEmitWithAwait ()
6180 if (arguments != null && arguments.ContainsEmitWithAwait ())
6183 return mg.ContainsEmitWithAwait ();
6186 public override Expression CreateExpressionTree (ResolveContext ec)
6188 Expression instance = mg.IsInstance ?
6189 mg.InstanceExpression.CreateExpressionTree (ec) :
6190 new NullLiteral (loc);
6192 var args = Arguments.CreateForExpressionTree (ec, arguments,
6194 mg.CreateExpressionTree (ec));
6196 return CreateExpressionFactoryCall (ec, "Call", args);
6199 protected override Expression DoResolve (ResolveContext ec)
6201 Expression member_expr;
6202 var atn = expr as ATypeNameExpression;
6204 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6205 if (member_expr != null)
6206 member_expr = member_expr.Resolve (ec);
6208 member_expr = expr.Resolve (ec);
6211 if (member_expr == null)
6215 // Next, evaluate all the expressions in the argument list
6217 bool dynamic_arg = false;
6218 if (arguments != null)
6219 arguments.Resolve (ec, out dynamic_arg);
6221 TypeSpec expr_type = member_expr.Type;
6222 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6223 return DoResolveDynamic (ec, member_expr);
6225 mg = member_expr as MethodGroupExpr;
6226 Expression invoke = null;
6229 if (expr_type != null && expr_type.IsDelegate) {
6230 invoke = new DelegateInvocation (member_expr, arguments, loc);
6231 invoke = invoke.Resolve (ec);
6232 if (invoke == null || !dynamic_arg)
6235 if (member_expr is RuntimeValueExpression) {
6236 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6237 member_expr.Type.GetSignatureForError ());
6241 MemberExpr me = member_expr as MemberExpr;
6243 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6247 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6248 member_expr.GetSignatureForError ());
6253 if (invoke == null) {
6254 mg = DoResolveOverload (ec);
6260 return DoResolveDynamic (ec, member_expr);
6262 var method = mg.BestCandidate;
6263 type = mg.BestCandidateReturnType;
6265 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6267 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6269 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6273 IsSpecialMethodInvocation (ec, method, loc);
6275 eclass = ExprClass.Value;
6279 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6282 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6284 args = dmb.Arguments;
6285 if (arguments != null)
6286 args.AddRange (arguments);
6287 } else if (mg == null) {
6288 if (arguments == null)
6289 args = new Arguments (1);
6293 args.Insert (0, new Argument (memberExpr));
6297 ec.Report.Error (1971, loc,
6298 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6303 if (arguments == null)
6304 args = new Arguments (1);
6308 MemberAccess ma = expr as MemberAccess;
6310 var left_type = ma.LeftExpression as TypeExpr;
6311 if (left_type != null) {
6312 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6315 // Any value type has to be pass as by-ref to get back the same
6316 // instance on which the member was called
6318 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6319 Argument.AType.Ref : Argument.AType.None;
6320 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6322 } else { // is SimpleName
6324 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6326 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6331 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6334 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6336 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6339 public override void FlowAnalysis (FlowAnalysisContext fc)
6341 if (mg.IsConditionallyExcluded)
6344 mg.FlowAnalysis (fc);
6346 if (arguments != null)
6347 arguments.FlowAnalysis (fc);
6350 public override string GetSignatureForError ()
6352 return mg.GetSignatureForError ();
6356 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6357 // or the type dynamic, then the member is invocable
6359 public static bool IsMemberInvocable (MemberSpec member)
6361 switch (member.Kind) {
6362 case MemberKind.Event:
6364 case MemberKind.Field:
6365 case MemberKind.Property:
6366 var m = member as IInterfaceMemberSpec;
6367 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6373 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6375 if (!method.IsReservedMethod)
6378 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6381 ec.Report.SymbolRelatedToPreviousError (method);
6382 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6383 method.GetSignatureForError ());
6388 public override void Emit (EmitContext ec)
6390 if (mg.IsConditionallyExcluded)
6393 mg.EmitCall (ec, arguments);
6396 public override void EmitStatement (EmitContext ec)
6401 // Pop the return value if there is one
6403 if (type.Kind != MemberKind.Void)
6404 ec.Emit (OpCodes.Pop);
6407 public override SLE.Expression MakeExpression (BuilderContext ctx)
6409 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6412 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6415 throw new NotSupportedException ();
6417 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6418 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6422 public override object Accept (StructuralVisitor visitor)
6424 return visitor.Visit (this);
6429 // Implements simple new expression
6431 public class New : ExpressionStatement, IMemoryLocation
6433 protected Arguments arguments;
6436 // During bootstrap, it contains the RequestedType,
6437 // but if `type' is not null, it *might* contain a NewDelegate
6438 // (because of field multi-initialization)
6440 protected Expression RequestedType;
6442 protected MethodSpec method;
6444 public New (Expression requested_type, Arguments arguments, Location l)
6446 RequestedType = requested_type;
6447 this.arguments = arguments;
6452 public Arguments Arguments {
6459 // Returns true for resolved `new S()'
6461 public bool IsDefaultStruct {
6463 return arguments == null && type.IsStruct && GetType () == typeof (New);
6467 public Expression TypeExpression {
6469 return RequestedType;
6476 /// Converts complex core type syntax like 'new int ()' to simple constant
6478 public static Constant Constantify (TypeSpec t, Location loc)
6480 switch (t.BuiltinType) {
6481 case BuiltinTypeSpec.Type.Int:
6482 return new IntConstant (t, 0, loc);
6483 case BuiltinTypeSpec.Type.UInt:
6484 return new UIntConstant (t, 0, loc);
6485 case BuiltinTypeSpec.Type.Long:
6486 return new LongConstant (t, 0, loc);
6487 case BuiltinTypeSpec.Type.ULong:
6488 return new ULongConstant (t, 0, loc);
6489 case BuiltinTypeSpec.Type.Float:
6490 return new FloatConstant (t, 0, loc);
6491 case BuiltinTypeSpec.Type.Double:
6492 return new DoubleConstant (t, 0, loc);
6493 case BuiltinTypeSpec.Type.Short:
6494 return new ShortConstant (t, 0, loc);
6495 case BuiltinTypeSpec.Type.UShort:
6496 return new UShortConstant (t, 0, loc);
6497 case BuiltinTypeSpec.Type.SByte:
6498 return new SByteConstant (t, 0, loc);
6499 case BuiltinTypeSpec.Type.Byte:
6500 return new ByteConstant (t, 0, loc);
6501 case BuiltinTypeSpec.Type.Char:
6502 return new CharConstant (t, '\0', loc);
6503 case BuiltinTypeSpec.Type.Bool:
6504 return new BoolConstant (t, false, loc);
6505 case BuiltinTypeSpec.Type.Decimal:
6506 return new DecimalConstant (t, 0, loc);
6510 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6512 if (t.IsNullableType)
6513 return Nullable.LiftedNull.Create (t, loc);
6518 public override bool ContainsEmitWithAwait ()
6520 return arguments != null && arguments.ContainsEmitWithAwait ();
6524 // Checks whether the type is an interface that has the
6525 // [ComImport, CoClass] attributes and must be treated
6528 public Expression CheckComImport (ResolveContext ec)
6530 if (!type.IsInterface)
6534 // Turn the call into:
6535 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6537 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6538 if (real_class == null)
6541 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6542 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6543 return cast.Resolve (ec);
6546 public override Expression CreateExpressionTree (ResolveContext ec)
6549 if (method == null) {
6550 args = new Arguments (1);
6551 args.Add (new Argument (new TypeOf (type, loc)));
6553 args = Arguments.CreateForExpressionTree (ec,
6554 arguments, new TypeOfMethod (method, loc));
6557 return CreateExpressionFactoryCall (ec, "New", args);
6560 protected override Expression DoResolve (ResolveContext ec)
6562 type = RequestedType.ResolveAsType (ec);
6566 eclass = ExprClass.Value;
6568 if (type.IsPointer) {
6569 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6570 type.GetSignatureForError ());
6574 if (arguments == null) {
6575 Constant c = Constantify (type, RequestedType.Location);
6577 return ReducedExpression.Create (c, this);
6580 if (type.IsDelegate) {
6581 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6584 var tparam = type as TypeParameterSpec;
6585 if (tparam != null) {
6587 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6588 // where type parameter constraint is inflated to struct
6590 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6591 ec.Report.Error (304, loc,
6592 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6593 type.GetSignatureForError ());
6596 if ((arguments != null) && (arguments.Count != 0)) {
6597 ec.Report.Error (417, loc,
6598 "`{0}': cannot provide arguments when creating an instance of a variable type",
6599 type.GetSignatureForError ());
6605 if (type.IsStatic) {
6606 ec.Report.SymbolRelatedToPreviousError (type);
6607 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6611 if (type.IsInterface || type.IsAbstract){
6612 if (!TypeManager.IsGenericType (type)) {
6613 RequestedType = CheckComImport (ec);
6614 if (RequestedType != null)
6615 return RequestedType;
6618 ec.Report.SymbolRelatedToPreviousError (type);
6619 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6624 // Any struct always defines parameterless constructor
6626 if (type.IsStruct && arguments == null)
6630 if (arguments != null) {
6631 arguments.Resolve (ec, out dynamic);
6636 method = ConstructorLookup (ec, type, ref arguments, loc);
6639 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6640 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6646 bool DoEmitTypeParameter (EmitContext ec)
6648 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6652 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6653 var tparam = (TypeParameterSpec) type;
6655 if (tparam.IsReferenceType) {
6656 ec.Emit (OpCodes.Call, ctor_factory);
6660 // Allow DoEmit() to be called multiple times.
6661 // We need to create a new LocalTemporary each time since
6662 // you can't share LocalBuilders among ILGeneators.
6663 LocalTemporary temp = new LocalTemporary (type);
6665 Label label_activator = ec.DefineLabel ();
6666 Label label_end = ec.DefineLabel ();
6668 temp.AddressOf (ec, AddressOp.Store);
6669 ec.Emit (OpCodes.Initobj, type);
6672 ec.Emit (OpCodes.Box, type);
6673 ec.Emit (OpCodes.Brfalse, label_activator);
6675 temp.AddressOf (ec, AddressOp.Store);
6676 ec.Emit (OpCodes.Initobj, type);
6679 ec.Emit (OpCodes.Br_S, label_end);
6681 ec.MarkLabel (label_activator);
6683 ec.Emit (OpCodes.Call, ctor_factory);
6684 ec.MarkLabel (label_end);
6689 // This Emit can be invoked in two contexts:
6690 // * As a mechanism that will leave a value on the stack (new object)
6691 // * As one that wont (init struct)
6693 // If we are dealing with a ValueType, we have a few
6694 // situations to deal with:
6696 // * The target is a ValueType, and we have been provided
6697 // the instance (this is easy, we are being assigned).
6699 // * The target of New is being passed as an argument,
6700 // to a boxing operation or a function that takes a
6703 // In this case, we need to create a temporary variable
6704 // that is the argument of New.
6706 // Returns whether a value is left on the stack
6708 // *** Implementation note ***
6710 // To benefit from this optimization, each assignable expression
6711 // has to manually cast to New and call this Emit.
6713 // TODO: It's worth to implement it for arrays and fields
6715 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6717 bool is_value_type = TypeSpec.IsValueType (type);
6718 VariableReference vr = target as VariableReference;
6720 if (target != null && is_value_type && (vr != null || method == null)) {
6721 target.AddressOf (ec, AddressOp.Store);
6722 } else if (vr != null && vr.IsRef) {
6726 if (arguments != null) {
6727 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6728 arguments = arguments.Emit (ec, false, true);
6730 arguments.Emit (ec);
6733 if (is_value_type) {
6734 if (method == null) {
6735 ec.Emit (OpCodes.Initobj, type);
6740 ec.MarkCallEntry (loc);
6741 ec.Emit (OpCodes.Call, method);
6746 if (type is TypeParameterSpec)
6747 return DoEmitTypeParameter (ec);
6749 ec.MarkCallEntry (loc);
6750 ec.Emit (OpCodes.Newobj, method);
6754 public override void Emit (EmitContext ec)
6756 LocalTemporary v = null;
6757 if (method == null && TypeSpec.IsValueType (type)) {
6758 // TODO: Use temporary variable from pool
6759 v = new LocalTemporary (type);
6766 public override void EmitStatement (EmitContext ec)
6768 LocalTemporary v = null;
6769 if (method == null && TypeSpec.IsValueType (type)) {
6770 // TODO: Use temporary variable from pool
6771 v = new LocalTemporary (type);
6775 ec.Emit (OpCodes.Pop);
6778 public override void FlowAnalysis (FlowAnalysisContext fc)
6780 if (arguments != null)
6781 arguments.FlowAnalysis (fc);
6784 public void AddressOf (EmitContext ec, AddressOp mode)
6786 EmitAddressOf (ec, mode);
6789 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6791 LocalTemporary value_target = new LocalTemporary (type);
6793 if (type is TypeParameterSpec) {
6794 DoEmitTypeParameter (ec);
6795 value_target.Store (ec);
6796 value_target.AddressOf (ec, mode);
6797 return value_target;
6800 value_target.AddressOf (ec, AddressOp.Store);
6802 if (method == null) {
6803 ec.Emit (OpCodes.Initobj, type);
6805 if (arguments != null)
6806 arguments.Emit (ec);
6808 ec.Emit (OpCodes.Call, method);
6811 value_target.AddressOf (ec, mode);
6812 return value_target;
6815 protected override void CloneTo (CloneContext clonectx, Expression t)
6817 New target = (New) t;
6819 target.RequestedType = RequestedType.Clone (clonectx);
6820 if (arguments != null){
6821 target.arguments = arguments.Clone (clonectx);
6825 public override SLE.Expression MakeExpression (BuilderContext ctx)
6828 return base.MakeExpression (ctx);
6830 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6834 public override object Accept (StructuralVisitor visitor)
6836 return visitor.Visit (this);
6841 // Array initializer expression, the expression is allowed in
6842 // variable or field initialization only which makes it tricky as
6843 // the type has to be infered based on the context either from field
6844 // type or variable type (think of multiple declarators)
6846 public class ArrayInitializer : Expression
6848 List<Expression> elements;
6849 BlockVariable variable;
6851 public ArrayInitializer (List<Expression> init, Location loc)
6857 public ArrayInitializer (int count, Location loc)
6858 : this (new List<Expression> (count), loc)
6862 public ArrayInitializer (Location loc)
6870 get { return elements.Count; }
6873 public List<Expression> Elements {
6879 public Expression this [int index] {
6881 return elements [index];
6885 public BlockVariable VariableDeclaration {
6896 public void Add (Expression expr)
6898 elements.Add (expr);
6901 public override bool ContainsEmitWithAwait ()
6903 throw new NotSupportedException ();
6906 public override Expression CreateExpressionTree (ResolveContext ec)
6908 throw new NotSupportedException ("ET");
6911 protected override void CloneTo (CloneContext clonectx, Expression t)
6913 var target = (ArrayInitializer) t;
6915 target.elements = new List<Expression> (elements.Count);
6916 foreach (var element in elements)
6917 target.elements.Add (element.Clone (clonectx));
6920 protected override Expression DoResolve (ResolveContext rc)
6922 var current_field = rc.CurrentMemberDefinition as FieldBase;
6923 TypeExpression type;
6924 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6925 type = new TypeExpression (current_field.MemberType, current_field.Location);
6926 } else if (variable != null) {
6927 if (variable.TypeExpression is VarExpr) {
6928 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6929 return EmptyExpression.Null;
6932 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6934 throw new NotImplementedException ("Unexpected array initializer context");
6937 return new ArrayCreation (type, this).Resolve (rc);
6940 public override void Emit (EmitContext ec)
6942 throw new InternalErrorException ("Missing Resolve call");
6945 public override void FlowAnalysis (FlowAnalysisContext fc)
6947 throw new InternalErrorException ("Missing Resolve call");
6950 public override object Accept (StructuralVisitor visitor)
6952 return visitor.Visit (this);
6957 /// 14.5.10.2: Represents an array creation expression.
6961 /// There are two possible scenarios here: one is an array creation
6962 /// expression that specifies the dimensions and optionally the
6963 /// initialization data and the other which does not need dimensions
6964 /// specified but where initialization data is mandatory.
6966 public class ArrayCreation : Expression
6968 FullNamedExpression requested_base_type;
6969 ArrayInitializer initializers;
6972 // The list of Argument types.
6973 // This is used to construct the `newarray' or constructor signature
6975 protected List<Expression> arguments;
6977 protected TypeSpec array_element_type;
6979 protected int dimensions;
6980 protected readonly ComposedTypeSpecifier rank;
6981 Expression first_emit;
6982 LocalTemporary first_emit_temp;
6984 protected List<Expression> array_data;
6986 Dictionary<int, int> bounds;
6989 // The number of constants in array initializers
6990 int const_initializers_count;
6991 bool only_constant_initializers;
6993 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6994 : this (requested_base_type, rank, initializers, l)
6996 arguments = new List<Expression> (exprs);
6997 num_arguments = arguments.Count;
7001 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7003 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7005 this.requested_base_type = requested_base_type;
7007 this.initializers = initializers;
7011 num_arguments = rank.Dimension;
7015 // For compiler generated single dimensional arrays only
7017 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7018 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7023 // For expressions like int[] foo = { 1, 2, 3 };
7025 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7026 : this (requested_base_type, null, initializers, initializers.Location)
7030 public ComposedTypeSpecifier Rank {
7036 public FullNamedExpression TypeExpression {
7038 return this.requested_base_type;
7042 public ArrayInitializer Initializers {
7044 return this.initializers;
7048 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7050 if (initializers != null && bounds == null) {
7052 // We use this to store all the data values in the order in which we
7053 // will need to store them in the byte blob later
7055 array_data = new List<Expression> (probe.Count);
7056 bounds = new Dictionary<int, int> ();
7059 if (specified_dims) {
7060 Expression a = arguments [idx];
7065 a = ConvertExpressionToArrayIndex (ec, a);
7071 if (initializers != null) {
7072 Constant c = a as Constant;
7073 if (c == null && a is ArrayIndexCast)
7074 c = ((ArrayIndexCast) a).Child as Constant;
7077 ec.Report.Error (150, a.Location, "A constant value is expected");
7083 value = System.Convert.ToInt32 (c.GetValue ());
7085 ec.Report.Error (150, a.Location, "A constant value is expected");
7089 // TODO: probe.Count does not fit ulong in
7090 if (value != probe.Count) {
7091 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7095 bounds[idx] = value;
7099 if (initializers == null)
7102 for (int i = 0; i < probe.Count; ++i) {
7104 if (o is ArrayInitializer) {
7105 var sub_probe = o as ArrayInitializer;
7106 if (idx + 1 >= dimensions){
7107 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7111 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7112 if (!bounds.ContainsKey(idx + 1))
7113 bounds[idx + 1] = sub_probe.Count;
7115 if (bounds[idx + 1] != sub_probe.Count) {
7116 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7120 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7123 } else if (child_bounds > 1) {
7124 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7126 Expression element = ResolveArrayElement (ec, o);
7127 if (element == null)
7130 // Initializers with the default values can be ignored
7131 Constant c = element as Constant;
7133 if (!c.IsDefaultInitializer (array_element_type)) {
7134 ++const_initializers_count;
7137 only_constant_initializers = false;
7140 array_data.Add (element);
7147 public override bool ContainsEmitWithAwait ()
7149 foreach (var arg in arguments) {
7150 if (arg.ContainsEmitWithAwait ())
7154 return InitializersContainAwait ();
7157 public override Expression CreateExpressionTree (ResolveContext ec)
7161 if (array_data == null) {
7162 args = new Arguments (arguments.Count + 1);
7163 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7164 foreach (Expression a in arguments)
7165 args.Add (new Argument (a.CreateExpressionTree (ec)));
7167 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7170 if (dimensions > 1) {
7171 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7175 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7176 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7177 if (array_data != null) {
7178 for (int i = 0; i < array_data.Count; ++i) {
7179 Expression e = array_data [i];
7180 args.Add (new Argument (e.CreateExpressionTree (ec)));
7184 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7187 void UpdateIndices (ResolveContext rc)
7190 for (var probe = initializers; probe != null;) {
7191 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7193 bounds[i++] = probe.Count;
7195 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7196 probe = (ArrayInitializer) probe[0];
7197 } else if (dimensions > i) {
7205 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7207 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7210 public override void FlowAnalysis (FlowAnalysisContext fc)
7212 foreach (var arg in arguments)
7213 arg.FlowAnalysis (fc);
7215 if (array_data != null) {
7216 foreach (var ad in array_data)
7217 ad.FlowAnalysis (fc);
7221 bool InitializersContainAwait ()
7223 if (array_data == null)
7226 foreach (var expr in array_data) {
7227 if (expr.ContainsEmitWithAwait ())
7234 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7236 element = element.Resolve (ec);
7237 if (element == null)
7240 if (element is CompoundAssign.TargetExpression) {
7241 if (first_emit != null)
7242 throw new InternalErrorException ("Can only handle one mutator at a time");
7243 first_emit = element;
7244 element = first_emit_temp = new LocalTemporary (element.Type);
7247 return Convert.ImplicitConversionRequired (
7248 ec, element, array_element_type, loc);
7251 protected bool ResolveInitializers (ResolveContext ec)
7254 only_constant_initializers = true;
7257 if (arguments != null) {
7259 for (int i = 0; i < arguments.Count; ++i) {
7260 res &= CheckIndices (ec, initializers, i, true, dimensions);
7261 if (initializers != null)
7268 arguments = new List<Expression> ();
7270 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7279 // Resolved the type of the array
7281 bool ResolveArrayType (ResolveContext ec)
7286 FullNamedExpression array_type_expr;
7287 if (num_arguments > 0) {
7288 array_type_expr = new ComposedCast (requested_base_type, rank);
7290 array_type_expr = requested_base_type;
7293 type = array_type_expr.ResolveAsType (ec);
7294 if (array_type_expr == null)
7297 var ac = type as ArrayContainer;
7299 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7303 array_element_type = ac.Element;
7304 dimensions = ac.Rank;
7309 protected override Expression DoResolve (ResolveContext ec)
7314 if (!ResolveArrayType (ec))
7318 // validate the initializers and fill in any missing bits
7320 if (!ResolveInitializers (ec))
7323 eclass = ExprClass.Value;
7327 byte [] MakeByteBlob ()
7332 int count = array_data.Count;
7334 TypeSpec element_type = array_element_type;
7335 if (element_type.IsEnum)
7336 element_type = EnumSpec.GetUnderlyingType (element_type);
7338 factor = BuiltinTypeSpec.GetSize (element_type);
7340 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7342 data = new byte [(count * factor + 3) & ~3];
7345 for (int i = 0; i < count; ++i) {
7346 var c = array_data[i] as Constant;
7352 object v = c.GetValue ();
7354 switch (element_type.BuiltinType) {
7355 case BuiltinTypeSpec.Type.Long:
7356 long lval = (long) v;
7358 for (int j = 0; j < factor; ++j) {
7359 data[idx + j] = (byte) (lval & 0xFF);
7363 case BuiltinTypeSpec.Type.ULong:
7364 ulong ulval = (ulong) v;
7366 for (int j = 0; j < factor; ++j) {
7367 data[idx + j] = (byte) (ulval & 0xFF);
7368 ulval = (ulval >> 8);
7371 case BuiltinTypeSpec.Type.Float:
7372 var fval = SingleConverter.SingleToInt32Bits((float) v);
7374 data[idx] = (byte) (fval & 0xff);
7375 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7376 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7377 data[idx + 3] = (byte) (fval >> 24);
7379 case BuiltinTypeSpec.Type.Double:
7380 element = BitConverter.GetBytes ((double) v);
7382 for (int j = 0; j < factor; ++j)
7383 data[idx + j] = element[j];
7385 // FIXME: Handle the ARM float format.
7386 if (!BitConverter.IsLittleEndian)
7387 System.Array.Reverse (data, idx, 8);
7389 case BuiltinTypeSpec.Type.Char:
7390 int chval = (int) ((char) v);
7392 data[idx] = (byte) (chval & 0xff);
7393 data[idx + 1] = (byte) (chval >> 8);
7395 case BuiltinTypeSpec.Type.Short:
7396 int sval = (int) ((short) v);
7398 data[idx] = (byte) (sval & 0xff);
7399 data[idx + 1] = (byte) (sval >> 8);
7401 case BuiltinTypeSpec.Type.UShort:
7402 int usval = (int) ((ushort) v);
7404 data[idx] = (byte) (usval & 0xff);
7405 data[idx + 1] = (byte) (usval >> 8);
7407 case BuiltinTypeSpec.Type.Int:
7410 data[idx] = (byte) (val & 0xff);
7411 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7412 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7413 data[idx + 3] = (byte) (val >> 24);
7415 case BuiltinTypeSpec.Type.UInt:
7416 uint uval = (uint) v;
7418 data[idx] = (byte) (uval & 0xff);
7419 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7420 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7421 data[idx + 3] = (byte) (uval >> 24);
7423 case BuiltinTypeSpec.Type.SByte:
7424 data[idx] = (byte) (sbyte) v;
7426 case BuiltinTypeSpec.Type.Byte:
7427 data[idx] = (byte) v;
7429 case BuiltinTypeSpec.Type.Bool:
7430 data[idx] = (byte) ((bool) v ? 1 : 0);
7432 case BuiltinTypeSpec.Type.Decimal:
7433 int[] bits = Decimal.GetBits ((decimal) v);
7436 // FIXME: For some reason, this doesn't work on the MS runtime.
7437 int[] nbits = new int[4];
7443 for (int j = 0; j < 4; j++) {
7444 data[p++] = (byte) (nbits[j] & 0xff);
7445 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7446 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7447 data[p++] = (byte) (nbits[j] >> 24);
7451 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7460 #if NET_4_0 || MOBILE_DYNAMIC
7461 public override SLE.Expression MakeExpression (BuilderContext ctx)
7464 return base.MakeExpression (ctx);
7466 var initializers = new SLE.Expression [array_data.Count];
7467 for (var i = 0; i < initializers.Length; i++) {
7468 if (array_data [i] == null)
7469 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7471 initializers [i] = array_data [i].MakeExpression (ctx);
7474 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7480 // Emits the initializers for the array
7482 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7484 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7489 // First, the static data
7491 byte [] data = MakeByteBlob ();
7492 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7494 if (stackArray == null) {
7495 ec.Emit (OpCodes.Dup);
7497 stackArray.Emit (ec);
7500 ec.Emit (OpCodes.Ldtoken, fb);
7501 ec.Emit (OpCodes.Call, m);
7506 // Emits pieces of the array that can not be computed at compile
7507 // time (variables and string locations).
7509 // This always expect the top value on the stack to be the array
7511 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
7513 int dims = bounds.Count;
7514 var current_pos = new int [dims];
7516 for (int i = 0; i < array_data.Count; i++){
7518 Expression e = array_data [i];
7519 var c = e as Constant;
7521 // Constant can be initialized via StaticInitializer
7522 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7526 if (stackArray != null) {
7527 if (e.ContainsEmitWithAwait ()) {
7528 e = e.EmitToField (ec);
7531 stackArray.EmitLoad (ec);
7533 ec.Emit (OpCodes.Dup);
7536 for (int idx = 0; idx < dims; idx++)
7537 ec.EmitInt (current_pos [idx]);
7540 // If we are dealing with a struct, get the
7541 // address of it, so we can store it.
7543 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
7544 ec.Emit (OpCodes.Ldelema, etype);
7548 ec.EmitArrayStore ((ArrayContainer) type);
7554 for (int j = dims - 1; j >= 0; j--){
7556 if (current_pos [j] < bounds [j])
7558 current_pos [j] = 0;
7562 if (stackArray != null)
7563 stackArray.PrepareCleanup (ec);
7566 public override void Emit (EmitContext ec)
7568 var await_field = EmitToFieldSource (ec);
7569 if (await_field != null)
7570 await_field.Emit (ec);
7573 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7575 if (first_emit != null) {
7576 first_emit.Emit (ec);
7577 first_emit_temp.Store (ec);
7580 StackFieldExpr await_stack_field;
7581 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7582 await_stack_field = ec.GetTemporaryField (type);
7585 await_stack_field = null;
7588 EmitExpressionsList (ec, arguments);
7590 ec.EmitArrayNew ((ArrayContainer) type);
7592 if (initializers == null)
7593 return await_stack_field;
7595 if (await_stack_field != null)
7596 await_stack_field.EmitAssignFromStack (ec);
7600 // Emit static initializer for arrays which contain more than 2 items and
7601 // the static initializer will initialize at least 25% of array values or there
7602 // is more than 10 items to be initialized
7604 // NOTE: const_initializers_count does not contain default constant values.
7606 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7607 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7608 EmitStaticInitializers (ec, await_stack_field);
7610 if (!only_constant_initializers)
7611 EmitDynamicInitializers (ec, false, await_stack_field);
7615 EmitDynamicInitializers (ec, true, await_stack_field);
7618 if (first_emit_temp != null)
7619 first_emit_temp.Release (ec);
7621 return await_stack_field;
7624 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
7626 // no multi dimensional or jagged arrays
7627 if (arguments.Count != 1 || array_element_type.IsArray) {
7628 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
7632 // No array covariance, except for array -> object
7633 if (type != targetType) {
7634 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7635 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
7639 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7640 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7645 // Single dimensional array of 0 size
7646 if (array_data == null) {
7647 IntConstant ic = arguments[0] as IntConstant;
7648 if (ic == null || !ic.IsDefaultValue) {
7649 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
7657 enc.Encode (array_data.Count);
7658 foreach (var element in array_data) {
7659 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
7663 protected override void CloneTo (CloneContext clonectx, Expression t)
7665 ArrayCreation target = (ArrayCreation) t;
7667 if (requested_base_type != null)
7668 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7670 if (arguments != null){
7671 target.arguments = new List<Expression> (arguments.Count);
7672 foreach (Expression e in arguments)
7673 target.arguments.Add (e.Clone (clonectx));
7676 if (initializers != null)
7677 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7680 public override object Accept (StructuralVisitor visitor)
7682 return visitor.Visit (this);
7687 // Represents an implicitly typed array epxression
7689 class ImplicitlyTypedArrayCreation : ArrayCreation
7691 TypeInferenceContext best_type_inference;
7693 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7694 : base (null, rank, initializers, loc)
7698 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7699 : base (null, initializers, loc)
7703 protected override Expression DoResolve (ResolveContext ec)
7708 dimensions = rank.Dimension;
7710 best_type_inference = new TypeInferenceContext ();
7712 if (!ResolveInitializers (ec))
7715 best_type_inference.FixAllTypes (ec);
7716 array_element_type = best_type_inference.InferredTypeArguments[0];
7717 best_type_inference = null;
7719 if (array_element_type == null ||
7720 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7721 arguments.Count != rank.Dimension) {
7722 ec.Report.Error (826, loc,
7723 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7728 // At this point we found common base type for all initializer elements
7729 // but we have to be sure that all static initializer elements are of
7732 UnifyInitializerElement (ec);
7734 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7735 eclass = ExprClass.Value;
7740 // Converts static initializer only
7742 void UnifyInitializerElement (ResolveContext ec)
7744 for (int i = 0; i < array_data.Count; ++i) {
7745 Expression e = array_data[i];
7747 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7751 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7753 element = element.Resolve (ec);
7754 if (element != null)
7755 best_type_inference.AddCommonTypeBound (element.Type);
7761 sealed class CompilerGeneratedThis : This
7763 public CompilerGeneratedThis (TypeSpec type, Location loc)
7767 eclass = ExprClass.Variable;
7770 protected override Expression DoResolve (ResolveContext ec)
7775 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7782 /// Represents the `this' construct
7785 public class This : VariableReference
7787 sealed class ThisVariable : ILocalVariable
7789 public static readonly ILocalVariable Instance = new ThisVariable ();
7791 public void Emit (EmitContext ec)
7796 public void EmitAssign (EmitContext ec)
7798 throw new InvalidOperationException ();
7801 public void EmitAddressOf (EmitContext ec)
7807 VariableInfo variable_info;
7809 public This (Location loc)
7816 public override string Name {
7817 get { return "this"; }
7820 public override bool IsLockedByStatement {
7828 public override bool IsRef {
7829 get { return type.IsStruct; }
7832 public override bool IsSideEffectFree {
7838 protected override ILocalVariable Variable {
7839 get { return ThisVariable.Instance; }
7842 public override VariableInfo VariableInfo {
7843 get { return variable_info; }
7846 public override bool IsFixed {
7847 get { return false; }
7852 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
7855 // It's null for all cases when we don't need to check `this'
7856 // definitive assignment
7858 if (variable_info == null)
7861 if (fc.IsDefinitelyAssigned (variable_info))
7864 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
7867 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7869 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7870 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7871 } else if (ec.CurrentAnonymousMethod != null) {
7872 ec.Report.Error (1673, loc,
7873 "Anonymous methods inside structs cannot access instance members of `this'. " +
7874 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7876 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7880 public override void FlowAnalysis (FlowAnalysisContext fc)
7882 CheckStructThisDefiniteAssignment (fc);
7885 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7890 AnonymousMethodStorey storey = ae.Storey;
7891 return storey != null ? storey.HoistedThis : null;
7894 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7896 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7899 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7902 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7908 public virtual void ResolveBase (ResolveContext ec)
7910 eclass = ExprClass.Variable;
7911 type = ec.CurrentType;
7913 if (!IsThisAvailable (ec, false)) {
7914 Error_ThisNotAvailable (ec);
7918 var block = ec.CurrentBlock;
7919 if (block != null) {
7920 var top = block.ParametersBlock.TopBlock;
7921 if (top.ThisVariable != null)
7922 variable_info = top.ThisVariable.VariableInfo;
7924 AnonymousExpression am = ec.CurrentAnonymousMethod;
7925 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7927 // Hoisted this is almost like hoisted variable but not exactly. When
7928 // there is no variable hoisted we can simply emit an instance method
7929 // without lifting this into a storey. Unfotunatelly this complicates
7930 // things in other cases because we don't know where this will be hoisted
7931 // until top-level block is fully resolved
7933 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7934 am.SetHasThisAccess ();
7939 protected override Expression DoResolve (ResolveContext ec)
7945 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7947 if (eclass == ExprClass.Unresolved)
7951 if (right_side == EmptyExpression.UnaryAddress)
7952 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7953 else if (right_side == EmptyExpression.OutAccess)
7954 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7956 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7962 public override int GetHashCode()
7964 throw new NotImplementedException ();
7967 public override bool Equals (object obj)
7969 This t = obj as This;
7976 protected override void CloneTo (CloneContext clonectx, Expression t)
7981 public override void SetHasAddressTaken ()
7986 public override object Accept (StructuralVisitor visitor)
7988 return visitor.Visit (this);
7993 /// Represents the `__arglist' construct
7995 public class ArglistAccess : Expression
7997 public ArglistAccess (Location loc)
8002 protected override void CloneTo (CloneContext clonectx, Expression target)
8007 public override bool ContainsEmitWithAwait ()
8012 public override Expression CreateExpressionTree (ResolveContext ec)
8014 throw new NotSupportedException ("ET");
8017 protected override Expression DoResolve (ResolveContext ec)
8019 eclass = ExprClass.Variable;
8020 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8022 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8023 ec.Report.Error (190, loc,
8024 "The __arglist construct is valid only within a variable argument method");
8030 public override void Emit (EmitContext ec)
8032 ec.Emit (OpCodes.Arglist);
8035 public override object Accept (StructuralVisitor visitor)
8037 return visitor.Visit (this);
8042 /// Represents the `__arglist (....)' construct
8044 public class Arglist : Expression
8046 Arguments arguments;
8048 public Arglist (Location loc)
8053 public Arglist (Arguments args, Location l)
8059 public Arguments Arguments {
8065 public MetaType[] ArgumentTypes {
8067 if (arguments == null)
8068 return MetaType.EmptyTypes;
8070 var retval = new MetaType[arguments.Count];
8071 for (int i = 0; i < retval.Length; i++)
8072 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8078 public override bool ContainsEmitWithAwait ()
8080 throw new NotImplementedException ();
8083 public override Expression CreateExpressionTree (ResolveContext ec)
8085 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8089 protected override Expression DoResolve (ResolveContext ec)
8091 eclass = ExprClass.Variable;
8092 type = InternalType.Arglist;
8093 if (arguments != null) {
8094 bool dynamic; // Can be ignored as there is always only 1 overload
8095 arguments.Resolve (ec, out dynamic);
8101 public override void Emit (EmitContext ec)
8103 if (arguments != null)
8104 arguments.Emit (ec);
8107 protected override void CloneTo (CloneContext clonectx, Expression t)
8109 Arglist target = (Arglist) t;
8111 if (arguments != null)
8112 target.arguments = arguments.Clone (clonectx);
8115 public override object Accept (StructuralVisitor visitor)
8117 return visitor.Visit (this);
8121 public class RefValueExpr : ShimExpression, IAssignMethod
8123 FullNamedExpression texpr;
8125 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8132 public FullNamedExpression TypeExpression {
8138 public override bool ContainsEmitWithAwait ()
8143 protected override Expression DoResolve (ResolveContext rc)
8145 expr = expr.Resolve (rc);
8146 type = texpr.ResolveAsType (rc);
8147 if (expr == null || type == null)
8150 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8151 eclass = ExprClass.Value;
8155 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8157 return DoResolve (rc);
8160 public override void Emit (EmitContext ec)
8163 ec.Emit (OpCodes.Refanyval, type);
8164 ec.EmitLoadFromPtr (type);
8167 public void Emit (EmitContext ec, bool leave_copy)
8169 throw new NotImplementedException ();
8172 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8175 ec.Emit (OpCodes.Refanyval, type);
8178 LocalTemporary temporary = null;
8180 ec.Emit (OpCodes.Dup);
8181 temporary = new LocalTemporary (source.Type);
8182 temporary.Store (ec);
8185 ec.EmitStoreFromPtr (type);
8187 if (temporary != null) {
8188 temporary.Emit (ec);
8189 temporary.Release (ec);
8193 public override object Accept (StructuralVisitor visitor)
8195 return visitor.Visit (this);
8199 public class RefTypeExpr : ShimExpression
8201 public RefTypeExpr (Expression expr, Location loc)
8207 protected override Expression DoResolve (ResolveContext rc)
8209 expr = expr.Resolve (rc);
8213 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8217 type = rc.BuiltinTypes.Type;
8218 eclass = ExprClass.Value;
8222 public override void Emit (EmitContext ec)
8225 ec.Emit (OpCodes.Refanytype);
8226 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8228 ec.Emit (OpCodes.Call, m);
8231 public override object Accept (StructuralVisitor visitor)
8233 return visitor.Visit (this);
8237 public class MakeRefExpr : ShimExpression
8239 public MakeRefExpr (Expression expr, Location loc)
8245 public override bool ContainsEmitWithAwait ()
8247 throw new NotImplementedException ();
8250 protected override Expression DoResolve (ResolveContext rc)
8252 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8253 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8254 eclass = ExprClass.Value;
8258 public override void Emit (EmitContext ec)
8260 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8261 ec.Emit (OpCodes.Mkrefany, expr.Type);
8264 public override object Accept (StructuralVisitor visitor)
8266 return visitor.Visit (this);
8271 /// Implements the typeof operator
8273 public class TypeOf : Expression {
8274 FullNamedExpression QueriedType;
8277 public TypeOf (FullNamedExpression queried_type, Location l)
8279 QueriedType = queried_type;
8284 // Use this constructor for any compiler generated typeof expression
8286 public TypeOf (TypeSpec type, Location loc)
8288 this.typearg = type;
8294 public override bool IsSideEffectFree {
8300 public TypeSpec TypeArgument {
8306 public FullNamedExpression TypeExpression {
8315 protected override void CloneTo (CloneContext clonectx, Expression t)
8317 TypeOf target = (TypeOf) t;
8318 if (QueriedType != null)
8319 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8322 public override bool ContainsEmitWithAwait ()
8327 public override Expression CreateExpressionTree (ResolveContext ec)
8329 Arguments args = new Arguments (2);
8330 args.Add (new Argument (this));
8331 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8332 return CreateExpressionFactoryCall (ec, "Constant", args);
8335 protected override Expression DoResolve (ResolveContext ec)
8337 if (eclass != ExprClass.Unresolved)
8340 if (typearg == null) {
8342 // Pointer types are allowed without explicit unsafe, they are just tokens
8344 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8345 typearg = QueriedType.ResolveAsType (ec);
8348 if (typearg == null)
8351 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8352 ec.Report.Error (1962, QueriedType.Location,
8353 "The typeof operator cannot be used on the dynamic type");
8357 type = ec.BuiltinTypes.Type;
8359 // Even though what is returned is a type object, it's treated as a value by the compiler.
8360 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8361 eclass = ExprClass.Value;
8365 static bool ContainsDynamicType (TypeSpec type)
8367 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8370 var element_container = type as ElementTypeSpec;
8371 if (element_container != null)
8372 return ContainsDynamicType (element_container.Element);
8374 foreach (var t in type.TypeArguments) {
8375 if (ContainsDynamicType (t)) {
8383 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8385 // Target type is not System.Type therefore must be object
8386 // and we need to use different encoding sequence
8387 if (targetType != type)
8390 if (typearg is InflatedTypeSpec) {
8393 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8394 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8395 typearg.GetSignatureForError ());
8399 gt = gt.DeclaringType;
8400 } while (gt != null);
8403 if (ContainsDynamicType (typearg)) {
8404 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8408 enc.EncodeTypeName (typearg);
8411 public override void Emit (EmitContext ec)
8413 ec.Emit (OpCodes.Ldtoken, typearg);
8414 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8416 ec.Emit (OpCodes.Call, m);
8419 public override object Accept (StructuralVisitor visitor)
8421 return visitor.Visit (this);
8425 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8427 public TypeOfMethod (MethodSpec method, Location loc)
8428 : base (method, loc)
8432 protected override Expression DoResolve (ResolveContext ec)
8434 if (member.IsConstructor) {
8435 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8437 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8443 return base.DoResolve (ec);
8446 public override void Emit (EmitContext ec)
8448 ec.Emit (OpCodes.Ldtoken, member);
8451 ec.Emit (OpCodes.Castclass, type);
8454 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8456 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8459 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8461 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8465 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8467 protected readonly T member;
8469 protected TypeOfMember (T member, Location loc)
8471 this.member = member;
8475 public override bool IsSideEffectFree {
8481 public override bool ContainsEmitWithAwait ()
8486 public override Expression CreateExpressionTree (ResolveContext ec)
8488 Arguments args = new Arguments (2);
8489 args.Add (new Argument (this));
8490 args.Add (new Argument (new TypeOf (type, loc)));
8491 return CreateExpressionFactoryCall (ec, "Constant", args);
8494 protected override Expression DoResolve (ResolveContext ec)
8496 eclass = ExprClass.Value;
8500 public override void Emit (EmitContext ec)
8502 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8503 PredefinedMember<MethodSpec> p;
8505 p = GetTypeFromHandleGeneric (ec);
8506 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8508 p = GetTypeFromHandle (ec);
8511 var mi = p.Resolve (loc);
8513 ec.Emit (OpCodes.Call, mi);
8516 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8517 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8520 sealed class TypeOfField : TypeOfMember<FieldSpec>
8522 public TypeOfField (FieldSpec field, Location loc)
8527 protected override Expression DoResolve (ResolveContext ec)
8529 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8533 return base.DoResolve (ec);
8536 public override void Emit (EmitContext ec)
8538 ec.Emit (OpCodes.Ldtoken, member);
8542 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8544 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8547 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8549 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8554 /// Implements the sizeof expression
8556 public class SizeOf : Expression {
8557 readonly Expression texpr;
8558 TypeSpec type_queried;
8560 public SizeOf (Expression queried_type, Location l)
8562 this.texpr = queried_type;
8566 public override bool IsSideEffectFree {
8572 public Expression TypeExpression {
8578 public override bool ContainsEmitWithAwait ()
8583 public override Expression CreateExpressionTree (ResolveContext ec)
8585 Error_PointerInsideExpressionTree (ec);
8589 protected override Expression DoResolve (ResolveContext ec)
8591 type_queried = texpr.ResolveAsType (ec);
8592 if (type_queried == null)
8595 if (type_queried.IsEnum)
8596 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8598 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8600 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8603 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8608 ec.Report.Error (233, loc,
8609 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8610 type_queried.GetSignatureForError ());
8613 type = ec.BuiltinTypes.Int;
8614 eclass = ExprClass.Value;
8618 public override void Emit (EmitContext ec)
8620 ec.Emit (OpCodes.Sizeof, type_queried);
8623 protected override void CloneTo (CloneContext clonectx, Expression t)
8627 public override object Accept (StructuralVisitor visitor)
8629 return visitor.Visit (this);
8634 /// Implements the qualified-alias-member (::) expression.
8636 public class QualifiedAliasMember : MemberAccess
8638 readonly string alias;
8639 public static readonly string GlobalAlias = "global";
8641 public QualifiedAliasMember (string alias, string identifier, Location l)
8642 : base (null, identifier, l)
8647 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8648 : base (null, identifier, targs, l)
8653 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8654 : base (null, identifier, arity, l)
8659 public string Alias {
8665 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8667 if (alias == GlobalAlias) {
8668 expr = new NamespaceExpression (ec.Module.GlobalRootNamespace, loc);
8669 return base.ResolveAsTypeOrNamespace (ec);
8672 int errors = ec.Module.Compiler.Report.Errors;
8673 expr = ec.LookupNamespaceAlias (alias);
8675 if (errors == ec.Module.Compiler.Report.Errors)
8676 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8680 return base.ResolveAsTypeOrNamespace (ec);
8683 protected override Expression DoResolve (ResolveContext ec)
8685 return ResolveAsTypeOrNamespace (ec);
8688 public override string GetSignatureForError ()
8691 if (targs != null) {
8692 name = Name + "<" + targs.GetSignatureForError () + ">";
8695 return alias + "::" + name;
8698 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8700 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8701 rc.Module.Compiler.Report.Error (687, loc,
8702 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8703 GetSignatureForError ());
8708 return DoResolve (rc);
8711 protected override void CloneTo (CloneContext clonectx, Expression t)
8716 public override object Accept (StructuralVisitor visitor)
8718 return visitor.Visit (this);
8723 /// Implements the member access expression
8725 public class MemberAccess : ATypeNameExpression
8727 protected Expression expr;
8729 public MemberAccess (Expression expr, string id)
8730 : base (id, expr.Location)
8735 public MemberAccess (Expression expr, string identifier, Location loc)
8736 : base (identifier, loc)
8741 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8742 : base (identifier, args, loc)
8747 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8748 : base (identifier, arity, loc)
8753 public Expression LeftExpression {
8759 public override Location StartLocation {
8761 return expr == null ? loc : expr.StartLocation;
8765 protected override Expression DoResolve (ResolveContext rc)
8767 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
8769 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8774 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8776 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
8778 if (e is TypeExpr) {
8779 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8784 e = e.ResolveLValue (rc, rhs);
8789 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8791 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8792 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8794 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8797 public static bool IsValidDotExpression (TypeSpec type)
8799 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8800 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8802 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8805 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8807 var sn = expr as SimpleName;
8808 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8811 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8814 // Resolve expression which does have type set as we need expression type
8815 // with disable flow analysis as we don't know whether left side expression
8816 // is used as variable or type
8818 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
8819 expr = expr.Resolve (rc);
8820 } else if (expr is TypeParameterExpr) {
8821 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8825 expr = expr.Resolve (rc, flags);
8831 var ns = expr as NamespaceExpression;
8833 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8835 if (retval == null) {
8836 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8840 if (HasTypeArguments)
8841 return new GenericTypeExpr (retval.Type, targs, loc);
8847 TypeSpec expr_type = expr.Type;
8848 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8849 me = expr as MemberExpr;
8851 me.ResolveInstanceExpression (rc, null);
8853 Arguments args = new Arguments (1);
8854 args.Add (new Argument (expr));
8855 return new DynamicMemberBinder (Name, args, loc);
8858 if (!IsValidDotExpression (expr_type)) {
8859 Error_OperatorCannotBeApplied (rc, expr_type);
8863 var lookup_arity = Arity;
8864 bool errorMode = false;
8865 Expression member_lookup;
8867 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8868 if (member_lookup == null) {
8870 // Try to look for extension method when member lookup failed
8872 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8873 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8874 if (methods != null) {
8875 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8876 if (HasTypeArguments) {
8877 if (!targs.Resolve (rc))
8880 emg.SetTypeArguments (rc, targs);
8883 // TODO: it should really skip the checks bellow
8884 return emg.Resolve (rc);
8890 if (member_lookup == null) {
8891 var dep = expr_type.GetMissingDependencies ();
8893 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8894 } else if (expr is TypeExpr) {
8895 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8897 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8903 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8904 // Leave it to overload resolution to report correct error
8905 } else if (!(member_lookup is TypeExpr)) {
8906 // TODO: rc.SymbolRelatedToPreviousError
8907 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8912 if (member_lookup != null)
8916 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8920 TypeExpr texpr = member_lookup as TypeExpr;
8921 if (texpr != null) {
8922 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8923 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8924 Name, texpr.GetSignatureForError ());
8927 if (!texpr.Type.IsAccessible (rc)) {
8928 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8929 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8933 if (HasTypeArguments) {
8934 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8937 return member_lookup;
8940 me = member_lookup as MemberExpr;
8942 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8946 me = me.ResolveMemberAccess (rc, expr, sn);
8949 if (!targs.Resolve (rc))
8952 me.SetTypeArguments (rc, targs);
8958 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8960 FullNamedExpression fexpr = expr as FullNamedExpression;
8961 if (fexpr == null) {
8962 expr.ResolveAsType (rc);
8966 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8968 if (expr_resolved == null)
8971 var ns = expr_resolved as NamespaceExpression;
8973 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8975 if (retval == null) {
8976 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8977 } else if (HasTypeArguments) {
8978 retval = new GenericTypeExpr (retval.Type, targs, loc);
8979 if (retval.ResolveAsType (rc) == null)
8986 var tnew_expr = expr_resolved.ResolveAsType (rc);
8987 if (tnew_expr == null)
8990 TypeSpec expr_type = tnew_expr;
8991 if (TypeManager.IsGenericParameter (expr_type)) {
8992 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8993 tnew_expr.GetSignatureForError ());
8997 var qam = this as QualifiedAliasMember;
8999 rc.Module.Compiler.Report.Error (431, loc,
9000 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9005 TypeSpec nested = null;
9006 while (expr_type != null) {
9007 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9008 if (nested == null) {
9009 if (expr_type == tnew_expr) {
9010 Error_IdentifierNotFound (rc, expr_type, Name);
9014 expr_type = tnew_expr;
9015 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9016 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9020 if (nested.IsAccessible (rc))
9024 // Keep looking after inaccessible candidate but only if
9025 // we are not in same context as the definition itself
9027 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9030 expr_type = expr_type.BaseType;
9035 if (HasTypeArguments) {
9036 texpr = new GenericTypeExpr (nested, targs, loc);
9038 texpr = new GenericOpenTypeExpr (nested, loc);
9041 texpr = new TypeExpression (nested, loc);
9044 if (texpr.ResolveAsType (rc) == null)
9050 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
9052 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9054 if (nested != null) {
9055 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9059 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9060 if (any_other_member != null) {
9061 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9065 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9066 Name, expr_type.GetSignatureForError ());
9069 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9071 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9074 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9076 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9077 ec.Report.SymbolRelatedToPreviousError (type);
9079 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9081 // a using directive or an assembly reference
9083 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9085 missing = "an assembly reference";
9088 ec.Report.Error (1061, loc,
9089 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9090 type.GetSignatureForError (), name, missing);
9094 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9097 public override string GetSignatureForError ()
9099 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9102 protected override void CloneTo (CloneContext clonectx, Expression t)
9104 MemberAccess target = (MemberAccess) t;
9106 target.expr = expr.Clone (clonectx);
9109 public override object Accept (StructuralVisitor visitor)
9111 return visitor.Visit (this);
9116 /// Implements checked expressions
9118 public class CheckedExpr : Expression {
9120 public Expression Expr;
9122 public CheckedExpr (Expression e, Location l)
9128 public override bool ContainsEmitWithAwait ()
9130 return Expr.ContainsEmitWithAwait ();
9133 public override Expression CreateExpressionTree (ResolveContext ec)
9135 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9136 return Expr.CreateExpressionTree (ec);
9139 protected override Expression DoResolve (ResolveContext ec)
9141 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9142 Expr = Expr.Resolve (ec);
9147 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9150 eclass = Expr.eclass;
9155 public override void Emit (EmitContext ec)
9157 using (ec.With (EmitContext.Options.CheckedScope, true))
9161 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9163 using (ec.With (EmitContext.Options.CheckedScope, true))
9164 Expr.EmitBranchable (ec, target, on_true);
9167 public override void FlowAnalysis (FlowAnalysisContext fc)
9169 Expr.FlowAnalysis (fc);
9172 public override SLE.Expression MakeExpression (BuilderContext ctx)
9174 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9175 return Expr.MakeExpression (ctx);
9179 protected override void CloneTo (CloneContext clonectx, Expression t)
9181 CheckedExpr target = (CheckedExpr) t;
9183 target.Expr = Expr.Clone (clonectx);
9186 public override object Accept (StructuralVisitor visitor)
9188 return visitor.Visit (this);
9193 /// Implements the unchecked expression
9195 public class UnCheckedExpr : Expression {
9197 public Expression Expr;
9199 public UnCheckedExpr (Expression e, Location l)
9205 public override bool ContainsEmitWithAwait ()
9207 return Expr.ContainsEmitWithAwait ();
9210 public override Expression CreateExpressionTree (ResolveContext ec)
9212 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9213 return Expr.CreateExpressionTree (ec);
9216 protected override Expression DoResolve (ResolveContext ec)
9218 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9219 Expr = Expr.Resolve (ec);
9224 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9227 eclass = Expr.eclass;
9232 public override void Emit (EmitContext ec)
9234 using (ec.With (EmitContext.Options.CheckedScope, false))
9238 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9240 using (ec.With (EmitContext.Options.CheckedScope, false))
9241 Expr.EmitBranchable (ec, target, on_true);
9244 public override void FlowAnalysis (FlowAnalysisContext fc)
9246 Expr.FlowAnalysis (fc);
9249 protected override void CloneTo (CloneContext clonectx, Expression t)
9251 UnCheckedExpr target = (UnCheckedExpr) t;
9253 target.Expr = Expr.Clone (clonectx);
9256 public override object Accept (StructuralVisitor visitor)
9258 return visitor.Visit (this);
9263 /// An Element Access expression.
9265 /// During semantic analysis these are transformed into
9266 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9268 public class ElementAccess : Expression
9270 public Arguments Arguments;
9271 public Expression Expr;
9273 public ElementAccess (Expression e, Arguments args, Location loc)
9277 this.Arguments = args;
9280 public override Location StartLocation {
9282 return Expr.StartLocation;
9286 public override bool ContainsEmitWithAwait ()
9288 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9292 // We perform some simple tests, and then to "split" the emit and store
9293 // code we create an instance of a different class, and return that.
9295 Expression CreateAccessExpression (ResolveContext ec)
9298 return (new ArrayAccess (this, loc));
9301 return MakePointerAccess (ec, type);
9303 FieldExpr fe = Expr as FieldExpr;
9305 var ff = fe.Spec as FixedFieldSpec;
9307 return MakePointerAccess (ec, ff.ElementType);
9311 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9312 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9313 return new IndexerExpr (indexers, type, this);
9316 if (type != InternalType.ErrorType) {
9317 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9318 type.GetSignatureForError ());
9324 public override Expression CreateExpressionTree (ResolveContext ec)
9326 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9327 Expr.CreateExpressionTree (ec));
9329 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9332 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
9334 if (Arguments.Count != 1){
9335 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
9339 var arg = Arguments[0];
9340 if (arg is NamedArgument)
9341 Error_NamedArgument ((NamedArgument) arg, rc.Report);
9343 var index = arg.Expr.Resolve (rc);
9347 index = ConvertExpressionToArrayIndex (rc, index, true);
9349 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
9350 return new Indirection (p, loc);
9353 protected override Expression DoResolve (ResolveContext ec)
9355 Expr = Expr.Resolve (ec);
9361 // TODO: Create 1 result for Resolve and ResolveLValue ?
9362 var res = CreateAccessExpression (ec);
9366 return res.Resolve (ec);
9369 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9371 Expr = Expr.Resolve (ec);
9377 var res = CreateAccessExpression (ec);
9381 return res.ResolveLValue (ec, rhs);
9384 public override void Emit (EmitContext ec)
9386 throw new Exception ("Should never be reached");
9389 public static void Error_NamedArgument (NamedArgument na, Report Report)
9391 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9394 public override void FlowAnalysis (FlowAnalysisContext fc)
9396 Expr.FlowAnalysis (fc);
9397 Arguments.FlowAnalysis (fc);
9400 public override string GetSignatureForError ()
9402 return Expr.GetSignatureForError ();
9405 protected override void CloneTo (CloneContext clonectx, Expression t)
9407 ElementAccess target = (ElementAccess) t;
9409 target.Expr = Expr.Clone (clonectx);
9410 if (Arguments != null)
9411 target.Arguments = Arguments.Clone (clonectx);
9414 public override object Accept (StructuralVisitor visitor)
9416 return visitor.Visit (this);
9421 /// Implements array access
9423 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9425 // Points to our "data" repository
9429 LocalTemporary temp;
9431 bool? has_await_args;
9433 public ArrayAccess (ElementAccess ea_data, Location l)
9439 public void AddressOf (EmitContext ec, AddressOp mode)
9441 var ac = (ArrayContainer) ea.Expr.Type;
9443 LoadInstanceAndArguments (ec, false, false);
9445 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9446 ec.Emit (OpCodes.Readonly);
9448 ec.EmitArrayAddress (ac);
9451 public override Expression CreateExpressionTree (ResolveContext ec)
9453 return ea.CreateExpressionTree (ec);
9456 public override bool ContainsEmitWithAwait ()
9458 return ea.ContainsEmitWithAwait ();
9461 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9463 return DoResolve (ec);
9466 protected override Expression DoResolve (ResolveContext ec)
9468 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9470 ea.Arguments.Resolve (ec, out dynamic);
9472 var ac = ea.Expr.Type as ArrayContainer;
9473 int rank = ea.Arguments.Count;
9474 if (ac.Rank != rank) {
9475 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9476 rank.ToString (), ac.Rank.ToString ());
9481 if (type.IsPointer && !ec.IsUnsafe) {
9482 UnsafeError (ec, ea.Location);
9485 foreach (Argument a in ea.Arguments) {
9486 if (a is NamedArgument)
9487 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9489 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9492 eclass = ExprClass.Variable;
9497 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9499 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9502 public override void FlowAnalysis (FlowAnalysisContext fc)
9504 ea.FlowAnalysis (fc);
9508 // Load the array arguments into the stack.
9510 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9513 ea.Expr = ea.Expr.EmitToField (ec);
9514 } else if (duplicateArguments) {
9516 ec.Emit (OpCodes.Dup);
9518 var copy = new LocalTemporary (ea.Expr.Type);
9525 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9526 if (dup_args != null)
9527 ea.Arguments = dup_args;
9530 public void Emit (EmitContext ec, bool leave_copy)
9532 var ac = ea.Expr.Type as ArrayContainer;
9535 ec.EmitLoadFromPtr (type);
9537 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9538 LoadInstanceAndArguments (ec, false, true);
9541 LoadInstanceAndArguments (ec, false, false);
9542 ec.EmitArrayLoad (ac);
9546 ec.Emit (OpCodes.Dup);
9547 temp = new LocalTemporary (this.type);
9552 public override void Emit (EmitContext ec)
9557 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9559 var ac = (ArrayContainer) ea.Expr.Type;
9560 TypeSpec t = source.Type;
9562 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9565 // When we are dealing with a struct, get the address of it to avoid value copy
9566 // Same cannot be done for reference type because array covariance and the
9567 // check in ldelema requires to specify the type of array element stored at the index
9569 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9570 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9572 if (has_await_args.Value) {
9573 if (source.ContainsEmitWithAwait ()) {
9574 source = source.EmitToField (ec);
9579 LoadInstanceAndArguments (ec, isCompound, false);
9584 ec.EmitArrayAddress (ac);
9587 ec.Emit (OpCodes.Dup);
9591 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9593 if (has_await_args.Value) {
9594 if (source.ContainsEmitWithAwait ())
9595 source = source.EmitToField (ec);
9597 LoadInstanceAndArguments (ec, false, false);
9604 var lt = ea.Expr as LocalTemporary;
9610 ec.Emit (OpCodes.Dup);
9611 temp = new LocalTemporary (this.type);
9616 ec.EmitStoreFromPtr (t);
9618 ec.EmitArrayStore (ac);
9627 public override Expression EmitToField (EmitContext ec)
9630 // Have to be specialized for arrays to get access to
9631 // underlying element. Instead of another result copy we
9632 // need direct access to element
9636 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9638 ea.Expr = ea.Expr.EmitToField (ec);
9642 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9644 #if NET_4_0 || MOBILE_DYNAMIC
9645 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9647 throw new NotImplementedException ();
9651 public override SLE.Expression MakeExpression (BuilderContext ctx)
9653 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9656 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9658 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9659 return Arguments.MakeExpression (ea.Arguments, ctx);
9665 // Indexer access expression
9667 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9669 IList<MemberSpec> indexers;
9670 Arguments arguments;
9671 TypeSpec queried_type;
9673 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9674 : base (ea.Location)
9676 this.indexers = indexers;
9677 this.queried_type = queriedType;
9678 this.InstanceExpression = ea.Expr;
9679 this.arguments = ea.Arguments;
9684 protected override Arguments Arguments {
9693 protected override TypeSpec DeclaringType {
9695 return best_candidate.DeclaringType;
9699 public override bool IsInstance {
9705 public override bool IsStatic {
9711 public override string KindName {
9712 get { return "indexer"; }
9715 public override string Name {
9723 public override bool ContainsEmitWithAwait ()
9725 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9728 public override Expression CreateExpressionTree (ResolveContext ec)
9730 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9731 InstanceExpression.CreateExpressionTree (ec),
9732 new TypeOfMethod (Getter, loc));
9734 return CreateExpressionFactoryCall (ec, "Call", args);
9737 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9739 LocalTemporary await_source_arg = null;
9742 emitting_compound_assignment = true;
9743 if (source is DynamicExpressionStatement) {
9748 emitting_compound_assignment = false;
9750 if (has_await_arguments) {
9751 await_source_arg = new LocalTemporary (Type);
9752 await_source_arg.Store (ec);
9754 arguments.Add (new Argument (await_source_arg));
9757 temp = await_source_arg;
9760 has_await_arguments = false;
9765 ec.Emit (OpCodes.Dup);
9766 temp = new LocalTemporary (Type);
9772 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9773 source = source.EmitToField (ec);
9775 temp = new LocalTemporary (Type);
9782 arguments.Add (new Argument (source));
9785 var call = new CallEmitter ();
9786 call.InstanceExpression = InstanceExpression;
9787 if (arguments == null)
9788 call.InstanceExpressionOnStack = true;
9790 call.Emit (ec, Setter, arguments, loc);
9795 } else if (leave_copy) {
9799 if (await_source_arg != null) {
9800 await_source_arg.Release (ec);
9804 public override void FlowAnalysis (FlowAnalysisContext fc)
9806 // TODO: Check the order
9807 base.FlowAnalysis (fc);
9808 arguments.FlowAnalysis (fc);
9811 public override string GetSignatureForError ()
9813 return best_candidate.GetSignatureForError ();
9816 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9819 throw new NotSupportedException ();
9821 var value = new[] { source.MakeExpression (ctx) };
9822 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9823 #if NET_4_0 || MOBILE_DYNAMIC
9824 return SLE.Expression.Block (
9825 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9828 return args.First ();
9833 public override SLE.Expression MakeExpression (BuilderContext ctx)
9836 return base.MakeExpression (ctx);
9838 var args = Arguments.MakeExpression (arguments, ctx);
9839 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9843 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9845 if (best_candidate != null)
9848 eclass = ExprClass.IndexerAccess;
9851 arguments.Resolve (rc, out dynamic);
9853 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9856 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9857 res.BaseMembersProvider = this;
9858 res.InstanceQualifier = this;
9860 // TODO: Do I need 2 argument sets?
9861 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9862 if (best_candidate != null)
9863 type = res.BestCandidateReturnType;
9864 else if (!res.BestCandidateIsDynamic)
9869 // It has dynamic arguments
9872 Arguments args = new Arguments (arguments.Count + 1);
9874 rc.Report.Error (1972, loc,
9875 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9877 args.Add (new Argument (InstanceExpression));
9879 args.AddRange (arguments);
9881 best_candidate = null;
9882 return new DynamicIndexBinder (args, loc);
9886 // Try to avoid resolving left expression again
9888 if (right_side != null)
9889 ResolveInstanceExpression (rc, right_side);
9894 protected override void CloneTo (CloneContext clonectx, Expression t)
9896 IndexerExpr target = (IndexerExpr) t;
9898 if (arguments != null)
9899 target.arguments = arguments.Clone (clonectx);
9902 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9904 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9907 #region IBaseMembersProvider Members
9909 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9911 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9914 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9916 if (queried_type == member.DeclaringType)
9919 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9920 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9923 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9932 // A base access expression
9934 public class BaseThis : This
9936 public BaseThis (Location loc)
9941 public BaseThis (TypeSpec type, Location loc)
9945 eclass = ExprClass.Variable;
9950 public override string Name {
9958 public override Expression CreateExpressionTree (ResolveContext ec)
9960 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9961 return base.CreateExpressionTree (ec);
9964 public override void Emit (EmitContext ec)
9968 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
9969 var context_type = ec.CurrentType;
9970 ec.Emit (OpCodes.Ldobj, context_type);
9971 ec.Emit (OpCodes.Box, context_type);
9975 protected override void Error_ThisNotAvailable (ResolveContext ec)
9978 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9980 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9984 public override void ResolveBase (ResolveContext ec)
9986 base.ResolveBase (ec);
9987 type = ec.CurrentType.BaseType;
9990 public override object Accept (StructuralVisitor visitor)
9992 return visitor.Visit (this);
9997 /// This class exists solely to pass the Type around and to be a dummy
9998 /// that can be passed to the conversion functions (this is used by
9999 /// foreach implementation to typecast the object return value from
10000 /// get_Current into the proper type. All code has been generated and
10001 /// we only care about the side effect conversions to be performed
10003 /// This is also now used as a placeholder where a no-action expression
10004 /// is needed (the `New' class).
10006 public class EmptyExpression : Expression
10008 sealed class OutAccessExpression : EmptyExpression
10010 public OutAccessExpression (TypeSpec t)
10015 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10017 rc.Report.Error (206, right_side.Location,
10018 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10024 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10025 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10026 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10027 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10028 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10029 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10030 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10031 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10033 public EmptyExpression (TypeSpec t)
10036 eclass = ExprClass.Value;
10037 loc = Location.Null;
10040 protected override void CloneTo (CloneContext clonectx, Expression target)
10044 public override bool ContainsEmitWithAwait ()
10049 public override Expression CreateExpressionTree (ResolveContext ec)
10051 throw new NotSupportedException ("ET");
10054 protected override Expression DoResolve (ResolveContext ec)
10059 public override void Emit (EmitContext ec)
10061 // nothing, as we only exist to not do anything.
10064 public override void EmitSideEffect (EmitContext ec)
10068 public override object Accept (StructuralVisitor visitor)
10070 return visitor.Visit (this);
10074 sealed class EmptyAwaitExpression : EmptyExpression
10076 public EmptyAwaitExpression (TypeSpec type)
10081 public override bool ContainsEmitWithAwait ()
10088 // Empty statement expression
10090 public sealed class EmptyExpressionStatement : ExpressionStatement
10092 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10094 private EmptyExpressionStatement ()
10096 loc = Location.Null;
10099 public override bool ContainsEmitWithAwait ()
10104 public override Expression CreateExpressionTree (ResolveContext ec)
10109 public override void EmitStatement (EmitContext ec)
10114 protected override Expression DoResolve (ResolveContext ec)
10116 eclass = ExprClass.Value;
10117 type = ec.BuiltinTypes.Object;
10121 public override void Emit (EmitContext ec)
10126 public override object Accept (StructuralVisitor visitor)
10128 return visitor.Visit (this);
10132 public class ErrorExpression : EmptyExpression
10134 public static readonly ErrorExpression Instance = new ErrorExpression ();
10136 private ErrorExpression ()
10137 : base (InternalType.ErrorType)
10141 public override Expression CreateExpressionTree (ResolveContext ec)
10146 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10151 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10155 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10159 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10163 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10167 public override object Accept (StructuralVisitor visitor)
10169 return visitor.Visit (this);
10173 public class UserCast : Expression {
10177 public UserCast (MethodSpec method, Expression source, Location l)
10179 if (source == null)
10180 throw new ArgumentNullException ("source");
10182 this.method = method;
10183 this.source = source;
10184 type = method.ReturnType;
10188 public Expression Source {
10194 public override bool ContainsEmitWithAwait ()
10196 return source.ContainsEmitWithAwait ();
10199 public override Expression CreateExpressionTree (ResolveContext ec)
10201 Arguments args = new Arguments (3);
10202 args.Add (new Argument (source.CreateExpressionTree (ec)));
10203 args.Add (new Argument (new TypeOf (type, loc)));
10204 args.Add (new Argument (new TypeOfMethod (method, loc)));
10205 return CreateExpressionFactoryCall (ec, "Convert", args);
10208 protected override Expression DoResolve (ResolveContext ec)
10210 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10212 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10214 eclass = ExprClass.Value;
10218 public override void Emit (EmitContext ec)
10221 ec.MarkCallEntry (loc);
10222 ec.Emit (OpCodes.Call, method);
10225 public override void FlowAnalysis (FlowAnalysisContext fc)
10227 source.FlowAnalysis (fc);
10230 public override string GetSignatureForError ()
10232 return TypeManager.CSharpSignature (method);
10235 public override SLE.Expression MakeExpression (BuilderContext ctx)
10238 return base.MakeExpression (ctx);
10240 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10246 // Holds additional type specifiers like ?, *, []
10248 public class ComposedTypeSpecifier
10250 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10252 public readonly int Dimension;
10253 public readonly Location Location;
10255 public ComposedTypeSpecifier (int specifier, Location loc)
10257 this.Dimension = specifier;
10258 this.Location = loc;
10262 public bool IsNullable {
10264 return Dimension == -1;
10268 public bool IsPointer {
10270 return Dimension == -2;
10274 public ComposedTypeSpecifier Next { get; set; }
10278 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10280 return new ComposedTypeSpecifier (dimension, loc);
10283 public static ComposedTypeSpecifier CreateNullable (Location loc)
10285 return new ComposedTypeSpecifier (-1, loc);
10288 public static ComposedTypeSpecifier CreatePointer (Location loc)
10290 return new ComposedTypeSpecifier (-2, loc);
10293 public string GetSignatureForError ()
10298 ArrayContainer.GetPostfixSignature (Dimension);
10300 return Next != null ? s + Next.GetSignatureForError () : s;
10305 // This class is used to "construct" the type during a typecast
10306 // operation. Since the Type.GetType class in .NET can parse
10307 // the type specification, we just use this to construct the type
10308 // one bit at a time.
10310 public class ComposedCast : TypeExpr {
10311 FullNamedExpression left;
10312 ComposedTypeSpecifier spec;
10314 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10317 throw new ArgumentNullException ("spec");
10321 this.loc = left.Location;
10324 public override TypeSpec ResolveAsType (IMemberContext ec)
10326 type = left.ResolveAsType (ec);
10330 eclass = ExprClass.Type;
10332 var single_spec = spec;
10334 if (single_spec.IsNullable) {
10335 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10339 single_spec = single_spec.Next;
10340 } else if (single_spec.IsPointer) {
10341 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10344 if (!ec.IsUnsafe) {
10345 UnsafeError (ec.Module.Compiler.Report, loc);
10349 type = PointerContainer.MakeType (ec.Module, type);
10350 single_spec = single_spec.Next;
10351 } while (single_spec != null && single_spec.IsPointer);
10354 if (single_spec != null && single_spec.Dimension > 0) {
10355 if (type.IsSpecialRuntimeType) {
10356 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10357 } else if (type.IsStatic) {
10358 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10359 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10360 type.GetSignatureForError ());
10362 MakeArray (ec.Module, single_spec);
10369 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10371 if (spec.Next != null)
10372 MakeArray (module, spec.Next);
10374 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10377 public override string GetSignatureForError ()
10379 return left.GetSignatureForError () + spec.GetSignatureForError ();
10382 public override object Accept (StructuralVisitor visitor)
10384 return visitor.Visit (this);
10388 class FixedBufferPtr : Expression
10390 readonly Expression array;
10392 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10394 this.type = array_type;
10395 this.array = array;
10399 public override bool ContainsEmitWithAwait ()
10401 throw new NotImplementedException ();
10404 public override Expression CreateExpressionTree (ResolveContext ec)
10406 Error_PointerInsideExpressionTree (ec);
10410 public override void Emit(EmitContext ec)
10415 protected override Expression DoResolve (ResolveContext ec)
10417 type = PointerContainer.MakeType (ec.Module, type);
10418 eclass = ExprClass.Value;
10425 // This class is used to represent the address of an array, used
10426 // only by the Fixed statement, this generates "&a [0]" construct
10427 // for fixed (char *pa = a)
10429 class ArrayPtr : FixedBufferPtr
10431 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10432 base (array, array_type, l)
10436 public override void Emit (EmitContext ec)
10441 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10446 // Encapsulates a conversion rules required for array indexes
10448 public class ArrayIndexCast : TypeCast
10450 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10451 : base (expr, returnType)
10453 if (expr.Type == returnType) // int -> int
10454 throw new ArgumentException ("unnecessary array index conversion");
10457 public override Expression CreateExpressionTree (ResolveContext ec)
10459 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10460 return base.CreateExpressionTree (ec);
10464 public override void Emit (EmitContext ec)
10468 switch (child.Type.BuiltinType) {
10469 case BuiltinTypeSpec.Type.UInt:
10470 ec.Emit (OpCodes.Conv_U);
10472 case BuiltinTypeSpec.Type.Long:
10473 ec.Emit (OpCodes.Conv_Ovf_I);
10475 case BuiltinTypeSpec.Type.ULong:
10476 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10479 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10485 // Implements the `stackalloc' keyword
10487 public class StackAlloc : Expression {
10492 public StackAlloc (Expression type, Expression count, Location l)
10495 this.count = count;
10499 public Expression TypeExpression {
10505 public Expression CountExpression {
10511 public override bool ContainsEmitWithAwait ()
10516 public override Expression CreateExpressionTree (ResolveContext ec)
10518 throw new NotSupportedException ("ET");
10521 protected override Expression DoResolve (ResolveContext ec)
10523 count = count.Resolve (ec);
10527 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10528 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10533 Constant c = count as Constant;
10534 if (c != null && c.IsNegative) {
10535 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10538 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10539 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10542 otype = t.ResolveAsType (ec);
10546 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10549 type = PointerContainer.MakeType (ec.Module, otype);
10550 eclass = ExprClass.Value;
10555 public override void Emit (EmitContext ec)
10557 int size = BuiltinTypeSpec.GetSize (otype);
10562 ec.Emit (OpCodes.Sizeof, otype);
10566 ec.Emit (OpCodes.Mul_Ovf_Un);
10567 ec.Emit (OpCodes.Localloc);
10570 protected override void CloneTo (CloneContext clonectx, Expression t)
10572 StackAlloc target = (StackAlloc) t;
10573 target.count = count.Clone (clonectx);
10574 target.t = t.Clone (clonectx);
10577 public override object Accept (StructuralVisitor visitor)
10579 return visitor.Visit (this);
10584 // An object initializer expression
10586 public class ElementInitializer : Assign
10588 public readonly string Name;
10590 public ElementInitializer (string name, Expression initializer, Location loc)
10591 : base (null, initializer, loc)
10596 protected override void CloneTo (CloneContext clonectx, Expression t)
10598 ElementInitializer target = (ElementInitializer) t;
10599 target.source = source.Clone (clonectx);
10602 public override Expression CreateExpressionTree (ResolveContext ec)
10604 Arguments args = new Arguments (2);
10605 FieldExpr fe = target as FieldExpr;
10607 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10609 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10612 Expression arg_expr;
10613 var cinit = source as CollectionOrObjectInitializers;
10614 if (cinit == null) {
10616 arg_expr = source.CreateExpressionTree (ec);
10618 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10619 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10622 args.Add (new Argument (arg_expr));
10623 return CreateExpressionFactoryCall (ec, mname, args);
10626 protected override Expression DoResolve (ResolveContext ec)
10628 if (source == null)
10629 return EmptyExpressionStatement.Instance;
10631 var t = ec.CurrentInitializerVariable.Type;
10632 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10633 Arguments args = new Arguments (1);
10634 args.Add (new Argument (ec.CurrentInitializerVariable));
10635 target = new DynamicMemberBinder (Name, args, loc);
10638 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10639 if (member == null) {
10640 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10642 if (member != null) {
10643 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10644 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10649 if (member == null) {
10650 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10654 if (!(member is PropertyExpr || member is FieldExpr)) {
10655 ec.Report.Error (1913, loc,
10656 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10657 member.GetSignatureForError ());
10662 var me = member as MemberExpr;
10664 ec.Report.Error (1914, loc,
10665 "Static field or property `{0}' cannot be assigned in an object initializer",
10666 me.GetSignatureForError ());
10670 me.InstanceExpression = ec.CurrentInitializerVariable;
10673 if (source is CollectionOrObjectInitializers) {
10674 Expression previous = ec.CurrentInitializerVariable;
10675 ec.CurrentInitializerVariable = target;
10676 source = source.Resolve (ec);
10677 ec.CurrentInitializerVariable = previous;
10678 if (source == null)
10681 eclass = source.eclass;
10682 type = source.Type;
10686 return base.DoResolve (ec);
10689 public override void EmitStatement (EmitContext ec)
10691 if (source is CollectionOrObjectInitializers)
10694 base.EmitStatement (ec);
10699 // A collection initializer expression
10701 class CollectionElementInitializer : Invocation
10703 public class ElementInitializerArgument : Argument
10705 public ElementInitializerArgument (Expression e)
10711 sealed class AddMemberAccess : MemberAccess
10713 public AddMemberAccess (Expression expr, Location loc)
10714 : base (expr, "Add", loc)
10718 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10720 if (TypeManager.HasElementType (type))
10723 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10727 public CollectionElementInitializer (Expression argument)
10728 : base (null, new Arguments (1))
10730 base.arguments.Add (new ElementInitializerArgument (argument));
10731 this.loc = argument.Location;
10734 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10735 : base (null, new Arguments (arguments.Count))
10737 foreach (Expression e in arguments)
10738 base.arguments.Add (new ElementInitializerArgument (e));
10743 public CollectionElementInitializer (Location loc)
10744 : base (null, null)
10749 public override Expression CreateExpressionTree (ResolveContext ec)
10751 Arguments args = new Arguments (2);
10752 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10754 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10755 foreach (Argument a in arguments)
10756 expr_initializers.Add (a.CreateExpressionTree (ec));
10758 args.Add (new Argument (new ArrayCreation (
10759 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10760 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10763 protected override void CloneTo (CloneContext clonectx, Expression t)
10765 CollectionElementInitializer target = (CollectionElementInitializer) t;
10766 if (arguments != null)
10767 target.arguments = arguments.Clone (clonectx);
10770 protected override Expression DoResolve (ResolveContext ec)
10772 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10774 return base.DoResolve (ec);
10779 // A block of object or collection initializers
10781 public class CollectionOrObjectInitializers : ExpressionStatement
10783 IList<Expression> initializers;
10784 bool is_collection_initialization;
10786 public CollectionOrObjectInitializers (Location loc)
10787 : this (new Expression[0], loc)
10791 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10793 this.initializers = initializers;
10797 public IList<Expression> Initializers {
10799 return initializers;
10803 public bool IsEmpty {
10805 return initializers.Count == 0;
10809 public bool IsCollectionInitializer {
10811 return is_collection_initialization;
10815 protected override void CloneTo (CloneContext clonectx, Expression target)
10817 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10819 t.initializers = new List<Expression> (initializers.Count);
10820 foreach (var e in initializers)
10821 t.initializers.Add (e.Clone (clonectx));
10824 public override bool ContainsEmitWithAwait ()
10826 foreach (var e in initializers) {
10827 if (e.ContainsEmitWithAwait ())
10834 public override Expression CreateExpressionTree (ResolveContext ec)
10836 return CreateExpressionTree (ec, false);
10839 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10841 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10842 foreach (Expression e in initializers) {
10843 Expression expr = e.CreateExpressionTree (ec);
10845 expr_initializers.Add (expr);
10849 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10851 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10854 protected override Expression DoResolve (ResolveContext ec)
10856 List<string> element_names = null;
10857 for (int i = 0; i < initializers.Count; ++i) {
10858 Expression initializer = initializers [i];
10859 ElementInitializer element_initializer = initializer as ElementInitializer;
10862 if (element_initializer != null) {
10863 element_names = new List<string> (initializers.Count);
10864 element_names.Add (element_initializer.Name);
10865 } else if (initializer is CompletingExpression){
10866 initializer.Resolve (ec);
10867 throw new InternalErrorException ("This line should never be reached");
10869 var t = ec.CurrentInitializerVariable.Type;
10870 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10871 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10872 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10873 "object initializer because type `{1}' does not implement `{2}' interface",
10874 ec.CurrentInitializerVariable.GetSignatureForError (),
10875 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10876 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10879 is_collection_initialization = true;
10882 if (is_collection_initialization != (element_initializer == null)) {
10883 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10884 is_collection_initialization ? "collection initializer" : "object initializer");
10888 if (!is_collection_initialization) {
10889 if (element_names.Contains (element_initializer.Name)) {
10890 ec.Report.Error (1912, element_initializer.Location,
10891 "An object initializer includes more than one member `{0}' initialization",
10892 element_initializer.Name);
10894 element_names.Add (element_initializer.Name);
10899 Expression e = initializer.Resolve (ec);
10900 if (e == EmptyExpressionStatement.Instance)
10901 initializers.RemoveAt (i--);
10903 initializers [i] = e;
10906 type = ec.CurrentInitializerVariable.Type;
10907 if (is_collection_initialization) {
10908 if (TypeManager.HasElementType (type)) {
10909 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10910 type.GetSignatureForError ());
10914 eclass = ExprClass.Variable;
10918 public override void Emit (EmitContext ec)
10920 EmitStatement (ec);
10923 public override void EmitStatement (EmitContext ec)
10925 foreach (ExpressionStatement e in initializers) {
10926 // TODO: need location region
10927 ec.Mark (e.Location);
10928 e.EmitStatement (ec);
10932 public override void FlowAnalysis (FlowAnalysisContext fc)
10934 foreach (var initializer in initializers)
10935 initializer.FlowAnalysis (fc);
10940 // New expression with element/object initializers
10942 public class NewInitialize : New
10945 // This class serves as a proxy for variable initializer target instances.
10946 // A real variable is assigned later when we resolve left side of an
10949 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10951 NewInitialize new_instance;
10953 public InitializerTargetExpression (NewInitialize newInstance)
10955 this.type = newInstance.type;
10956 this.loc = newInstance.loc;
10957 this.eclass = newInstance.eclass;
10958 this.new_instance = newInstance;
10961 public override bool ContainsEmitWithAwait ()
10966 public override Expression CreateExpressionTree (ResolveContext ec)
10968 // Should not be reached
10969 throw new NotSupportedException ("ET");
10972 protected override Expression DoResolve (ResolveContext ec)
10977 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10982 public override void Emit (EmitContext ec)
10984 Expression e = (Expression) new_instance.instance;
10988 public override Expression EmitToField (EmitContext ec)
10990 return (Expression) new_instance.instance;
10993 #region IMemoryLocation Members
10995 public void AddressOf (EmitContext ec, AddressOp mode)
10997 new_instance.instance.AddressOf (ec, mode);
11003 CollectionOrObjectInitializers initializers;
11004 IMemoryLocation instance;
11005 DynamicExpressionStatement dynamic;
11007 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
11008 : base (requested_type, arguments, l)
11010 this.initializers = initializers;
11013 public CollectionOrObjectInitializers Initializers {
11015 return initializers;
11019 protected override void CloneTo (CloneContext clonectx, Expression t)
11021 base.CloneTo (clonectx, t);
11023 NewInitialize target = (NewInitialize) t;
11024 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
11027 public override bool ContainsEmitWithAwait ()
11029 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
11032 public override Expression CreateExpressionTree (ResolveContext ec)
11034 Arguments args = new Arguments (2);
11035 args.Add (new Argument (base.CreateExpressionTree (ec)));
11036 if (!initializers.IsEmpty)
11037 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
11039 return CreateExpressionFactoryCall (ec,
11040 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
11044 protected override Expression DoResolve (ResolveContext ec)
11046 Expression e = base.DoResolve (ec);
11050 if (type.IsDelegate) {
11051 ec.Report.Error (1958, Initializers.Location,
11052 "Object and collection initializers cannot be used to instantiate a delegate");
11055 Expression previous = ec.CurrentInitializerVariable;
11056 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
11057 initializers.Resolve (ec);
11058 ec.CurrentInitializerVariable = previous;
11060 dynamic = e as DynamicExpressionStatement;
11061 if (dynamic != null)
11067 public override void Emit (EmitContext ec)
11069 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11070 var fe = ec.GetTemporaryField (type);
11072 if (!Emit (ec, fe))
11081 public override bool Emit (EmitContext ec, IMemoryLocation target)
11083 bool left_on_stack;
11084 if (dynamic != null) {
11086 left_on_stack = true;
11088 left_on_stack = base.Emit (ec, target);
11091 if (initializers.IsEmpty)
11092 return left_on_stack;
11094 LocalTemporary temp = null;
11096 instance = target as LocalTemporary;
11097 if (instance == null)
11098 instance = target as StackFieldExpr;
11100 if (instance == null) {
11101 if (!left_on_stack) {
11102 VariableReference vr = target as VariableReference;
11104 // FIXME: This still does not work correctly for pre-set variables
11105 if (vr != null && vr.IsRef)
11106 target.AddressOf (ec, AddressOp.Load);
11108 ((Expression) target).Emit (ec);
11109 left_on_stack = true;
11112 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11113 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
11115 temp = new LocalTemporary (type);
11120 if (left_on_stack && temp != null)
11123 initializers.Emit (ec);
11125 if (left_on_stack) {
11126 if (temp != null) {
11130 ((Expression) instance).Emit (ec);
11134 return left_on_stack;
11137 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
11139 instance = base.EmitAddressOf (ec, Mode);
11141 if (!initializers.IsEmpty)
11142 initializers.Emit (ec);
11147 public override void FlowAnalysis (FlowAnalysisContext fc)
11149 base.FlowAnalysis (fc);
11150 initializers.FlowAnalysis (fc);
11153 public override object Accept (StructuralVisitor visitor)
11155 return visitor.Visit (this);
11159 public class NewAnonymousType : New
11161 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
11163 List<AnonymousTypeParameter> parameters;
11164 readonly TypeContainer parent;
11165 AnonymousTypeClass anonymous_type;
11167 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11168 : base (null, null, loc)
11170 this.parameters = parameters;
11171 this.parent = parent;
11174 public List<AnonymousTypeParameter> Parameters {
11176 return this.parameters;
11180 protected override void CloneTo (CloneContext clonectx, Expression target)
11182 if (parameters == null)
11185 NewAnonymousType t = (NewAnonymousType) target;
11186 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11187 foreach (AnonymousTypeParameter atp in parameters)
11188 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11191 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11193 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11197 type = AnonymousTypeClass.Create (parent, parameters, loc);
11201 int errors = ec.Report.Errors;
11202 type.CreateContainer ();
11203 type.DefineContainer ();
11205 if ((ec.Report.Errors - errors) == 0) {
11206 parent.Module.AddAnonymousType (type);
11207 type.PrepareEmit ();
11213 public override Expression CreateExpressionTree (ResolveContext ec)
11215 if (parameters == null)
11216 return base.CreateExpressionTree (ec);
11218 var init = new ArrayInitializer (parameters.Count, loc);
11219 foreach (var m in anonymous_type.Members) {
11220 var p = m as Property;
11222 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11225 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11226 foreach (Argument a in arguments)
11227 ctor_args.Add (a.CreateExpressionTree (ec));
11229 Arguments args = new Arguments (3);
11230 args.Add (new Argument (new TypeOfMethod (method, loc)));
11231 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11232 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11234 return CreateExpressionFactoryCall (ec, "New", args);
11237 protected override Expression DoResolve (ResolveContext ec)
11239 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11240 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11244 if (parameters == null) {
11245 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11246 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11247 return base.DoResolve (ec);
11250 bool error = false;
11251 arguments = new Arguments (parameters.Count);
11252 var t_args = new TypeSpec [parameters.Count];
11253 for (int i = 0; i < parameters.Count; ++i) {
11254 Expression e = parameters [i].Resolve (ec);
11260 arguments.Add (new Argument (e));
11261 t_args [i] = e.Type;
11267 anonymous_type = CreateAnonymousType (ec, parameters);
11268 if (anonymous_type == null)
11271 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11272 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11273 eclass = ExprClass.Value;
11277 public override object Accept (StructuralVisitor visitor)
11279 return visitor.Visit (this);
11283 public class AnonymousTypeParameter : ShimExpression
11285 public readonly string Name;
11287 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11288 : base (initializer)
11294 public AnonymousTypeParameter (Parameter parameter)
11295 : base (new SimpleName (parameter.Name, parameter.Location))
11297 this.Name = parameter.Name;
11298 this.loc = parameter.Location;
11301 public override bool Equals (object o)
11303 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11304 return other != null && Name == other.Name;
11307 public override int GetHashCode ()
11309 return Name.GetHashCode ();
11312 protected override Expression DoResolve (ResolveContext ec)
11314 Expression e = expr.Resolve (ec);
11318 if (e.eclass == ExprClass.MethodGroup) {
11319 Error_InvalidInitializer (ec, e.ExprClassName);
11324 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11325 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11332 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11334 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11335 Name, initializer);
11339 public class CatchFilterExpression : BooleanExpression
11341 public CatchFilterExpression (Expression expr, Location loc)