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 (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1436 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1437 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1442 if (expr.Type == InternalType.AnonymousMethod) {
1443 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1451 public override void FlowAnalysis (FlowAnalysisContext fc)
1453 expr.FlowAnalysis (fc);
1456 protected abstract string OperatorName { get; }
1458 protected override void CloneTo (CloneContext clonectx, Expression t)
1460 Probe target = (Probe) t;
1462 target.expr = expr.Clone (clonectx);
1463 target.ProbeType = ProbeType.Clone (clonectx);
1469 /// Implementation of the `is' operator.
1471 public class Is : Probe
1473 Nullable.Unwrap expr_unwrap;
1475 public Is (Expression expr, Expression probe_type, Location l)
1476 : base (expr, probe_type, l)
1480 protected override string OperatorName {
1481 get { return "is"; }
1484 public override Expression CreateExpressionTree (ResolveContext ec)
1486 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1487 expr.CreateExpressionTree (ec),
1488 new TypeOf (probe_type_expr, loc));
1490 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1493 public override void Emit (EmitContext ec)
1495 if (expr_unwrap != null) {
1496 expr_unwrap.EmitCheck (ec);
1502 // Only to make verifier happy
1503 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1504 ec.Emit (OpCodes.Box, expr.Type);
1506 ec.Emit (OpCodes.Isinst, probe_type_expr);
1508 ec.Emit (OpCodes.Cgt_Un);
1511 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1513 if (expr_unwrap != null) {
1514 expr_unwrap.EmitCheck (ec);
1517 ec.Emit (OpCodes.Isinst, probe_type_expr);
1519 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1522 Expression CreateConstantResult (ResolveContext ec, bool result)
1525 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1526 probe_type_expr.GetSignatureForError ());
1528 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1529 probe_type_expr.GetSignatureForError ());
1531 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1534 protected override Expression DoResolve (ResolveContext ec)
1536 if (base.DoResolve (ec) == null)
1539 TypeSpec d = expr.Type;
1540 bool d_is_nullable = false;
1543 // If E is a method group or the null literal, or if the type of E is a reference
1544 // type or a nullable type and the value of E is null, the result is false
1546 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1547 return CreateConstantResult (ec, false);
1549 if (d.IsNullableType) {
1550 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1551 if (!ut.IsGenericParameter) {
1553 d_is_nullable = true;
1557 type = ec.BuiltinTypes.Bool;
1558 eclass = ExprClass.Value;
1559 TypeSpec t = probe_type_expr;
1560 bool t_is_nullable = false;
1561 if (t.IsNullableType) {
1562 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1563 if (!ut.IsGenericParameter) {
1565 t_is_nullable = true;
1572 // D and T are the same value types but D can be null
1574 if (d_is_nullable && !t_is_nullable) {
1575 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1580 // The result is true if D and T are the same value types
1582 return CreateConstantResult (ec, true);
1585 var tp = d as TypeParameterSpec;
1587 return ResolveGenericParameter (ec, t, tp);
1590 // An unboxing conversion exists
1592 if (Convert.ExplicitReferenceConversionExists (d, t))
1596 // open generic type
1598 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1601 var tps = t as TypeParameterSpec;
1603 return ResolveGenericParameter (ec, d, tps);
1605 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1606 ec.Report.Warning (1981, 3, loc,
1607 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1608 OperatorName, t.GetSignatureForError ());
1611 if (TypeManager.IsGenericParameter (d))
1612 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1614 if (TypeSpec.IsValueType (d)) {
1615 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1616 if (d_is_nullable && !t_is_nullable) {
1617 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1621 return CreateConstantResult (ec, true);
1624 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1625 var c = expr as Constant;
1627 return CreateConstantResult (ec, !c.IsNull);
1630 // Do not optimize for imported type or dynamic type
1632 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1633 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1637 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1641 // Turn is check into simple null check for implicitly convertible reference types
1643 return ReducedExpression.Create (
1644 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1648 if (Convert.ExplicitReferenceConversionExists (d, t))
1652 // open generic type
1654 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1659 return CreateConstantResult (ec, false);
1662 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1664 if (t.IsReferenceType) {
1666 return CreateConstantResult (ec, false);
1669 if (expr.Type.IsGenericParameter) {
1670 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1671 return CreateConstantResult (ec, true);
1673 expr = new BoxedCast (expr, d);
1679 public override object Accept (StructuralVisitor visitor)
1681 return visitor.Visit (this);
1686 /// Implementation of the `as' operator.
1688 public class As : Probe {
1689 Expression resolved_type;
1691 public As (Expression expr, Expression probe_type, Location l)
1692 : base (expr, probe_type, l)
1696 protected override string OperatorName {
1697 get { return "as"; }
1700 public override Expression CreateExpressionTree (ResolveContext ec)
1702 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1703 expr.CreateExpressionTree (ec),
1704 new TypeOf (probe_type_expr, loc));
1706 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1709 public override void Emit (EmitContext ec)
1713 ec.Emit (OpCodes.Isinst, type);
1715 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1716 ec.Emit (OpCodes.Unbox_Any, type);
1719 protected override Expression DoResolve (ResolveContext ec)
1721 if (resolved_type == null) {
1722 resolved_type = base.DoResolve (ec);
1724 if (resolved_type == null)
1728 type = probe_type_expr;
1729 eclass = ExprClass.Value;
1730 TypeSpec etype = expr.Type;
1732 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1733 if (TypeManager.IsGenericParameter (type)) {
1734 ec.Report.Error (413, loc,
1735 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1736 probe_type_expr.GetSignatureForError ());
1738 ec.Report.Error (77, loc,
1739 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1740 type.GetSignatureForError ());
1745 if (expr.IsNull && type.IsNullableType) {
1746 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1749 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1750 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1754 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1756 e = EmptyCast.Create (e, type);
1757 return ReducedExpression.Create (e, this).Resolve (ec);
1760 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1761 if (TypeManager.IsGenericParameter (etype))
1762 expr = new BoxedCast (expr, etype);
1767 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1768 expr = new BoxedCast (expr, etype);
1772 if (etype != InternalType.ErrorType) {
1773 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1774 etype.GetSignatureForError (), type.GetSignatureForError ());
1780 public override object Accept (StructuralVisitor visitor)
1782 return visitor.Visit (this);
1787 // This represents a typecast in the source language.
1789 public class Cast : ShimExpression {
1790 Expression target_type;
1792 public Cast (Expression cast_type, Expression expr, Location loc)
1795 this.target_type = cast_type;
1799 public Expression TargetType {
1800 get { return target_type; }
1803 protected override Expression DoResolve (ResolveContext ec)
1805 expr = expr.Resolve (ec);
1809 type = target_type.ResolveAsType (ec);
1813 if (type.IsStatic) {
1814 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
1818 if (type.IsPointer && !ec.IsUnsafe) {
1819 UnsafeError (ec, loc);
1822 eclass = ExprClass.Value;
1824 Constant c = expr as Constant;
1826 c = c.Reduce (ec, type);
1831 var res = Convert.ExplicitConversion (ec, expr, type, loc);
1833 return EmptyCast.Create (res, type);
1838 protected override void CloneTo (CloneContext clonectx, Expression t)
1840 Cast target = (Cast) t;
1842 target.target_type = target_type.Clone (clonectx);
1843 target.expr = expr.Clone (clonectx);
1846 public override object Accept (StructuralVisitor visitor)
1848 return visitor.Visit (this);
1852 public class ImplicitCast : ShimExpression
1856 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1859 this.loc = expr.Location;
1861 this.arrayAccess = arrayAccess;
1864 protected override Expression DoResolve (ResolveContext ec)
1866 expr = expr.Resolve (ec);
1871 expr = ConvertExpressionToArrayIndex (ec, expr);
1873 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1880 // C# 2.0 Default value expression
1882 public class DefaultValueExpression : Expression
1886 public DefaultValueExpression (Expression expr, Location loc)
1892 public Expression Expr {
1898 public override bool IsSideEffectFree {
1904 public override bool ContainsEmitWithAwait ()
1909 public override Expression CreateExpressionTree (ResolveContext ec)
1911 Arguments args = new Arguments (2);
1912 args.Add (new Argument (this));
1913 args.Add (new Argument (new TypeOf (type, loc)));
1914 return CreateExpressionFactoryCall (ec, "Constant", args);
1917 protected override Expression DoResolve (ResolveContext ec)
1919 type = expr.ResolveAsType (ec);
1923 if (type.IsStatic) {
1924 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1928 return new NullLiteral (Location).ConvertImplicitly (type);
1930 if (TypeSpec.IsReferenceType (type))
1931 return new NullConstant (type, loc);
1933 Constant c = New.Constantify (type, expr.Location);
1937 eclass = ExprClass.Variable;
1941 public override void Emit (EmitContext ec)
1943 LocalTemporary temp_storage = new LocalTemporary(type);
1945 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1946 ec.Emit(OpCodes.Initobj, type);
1947 temp_storage.Emit(ec);
1948 temp_storage.Release (ec);
1951 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
1952 public override SLE.Expression MakeExpression (BuilderContext ctx)
1954 return SLE.Expression.Default (type.GetMetaInfo ());
1958 protected override void CloneTo (CloneContext clonectx, Expression t)
1960 DefaultValueExpression target = (DefaultValueExpression) t;
1962 target.expr = expr.Clone (clonectx);
1965 public override object Accept (StructuralVisitor visitor)
1967 return visitor.Visit (this);
1972 /// Binary operators
1974 public class Binary : Expression, IDynamicBinder
1976 public class PredefinedOperator
1978 protected readonly TypeSpec left;
1979 protected readonly TypeSpec right;
1980 protected readonly TypeSpec left_unwrap;
1981 protected readonly TypeSpec right_unwrap;
1982 public readonly Operator OperatorsMask;
1983 public TypeSpec ReturnType;
1985 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1986 : this (ltype, rtype, op_mask, ltype)
1990 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1991 : this (type, type, op_mask, return_type)
1995 public PredefinedOperator (TypeSpec type, Operator op_mask)
1996 : this (type, type, op_mask, type)
2000 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2002 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2003 throw new InternalErrorException ("Only masked values can be used");
2005 if ((op_mask & Operator.NullableMask) != 0) {
2006 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2007 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2009 left_unwrap = ltype;
2010 right_unwrap = rtype;
2015 this.OperatorsMask = op_mask;
2016 this.ReturnType = return_type;
2019 public bool IsLifted {
2021 return (OperatorsMask & Operator.NullableMask) != 0;
2025 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2029 var left_expr = b.left;
2030 var right_expr = b.right;
2032 b.type = ReturnType;
2035 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2036 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2037 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2040 if (right_expr.IsNull) {
2041 if ((b.oper & Operator.EqualityMask) != 0) {
2042 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2043 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2044 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2045 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2046 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2048 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2049 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2051 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2052 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2054 return b.CreateLiftedValueTypeResult (rc, left);
2056 } else if (left_expr.IsNull) {
2057 if ((b.oper & Operator.EqualityMask) != 0) {
2058 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2059 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2060 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2061 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2062 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2064 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2065 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2067 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2068 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2070 return b.CreateLiftedValueTypeResult (rc, right);
2076 // A user operators does not support multiple user conversions, but decimal type
2077 // is considered to be predefined type therefore we apply predefined operators rules
2078 // and then look for decimal user-operator implementation
2080 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2081 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2082 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2084 return b.ResolveUserOperator (rc, b.left, b.right);
2087 c = right_expr as Constant;
2089 if (c.IsDefaultValue) {
2093 // (expr + 0) to expr
2094 // (expr - 0) to expr
2095 // (bool? | false) to bool?
2097 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2098 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2099 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2100 return ReducedExpression.Create (b.left, b).Resolve (rc);
2104 // Optimizes (value &/&& 0) to 0
2106 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2107 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2108 return ReducedExpression.Create (side_effect, b);
2112 // Optimizes (bool? & true) to bool?
2114 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2115 return ReducedExpression.Create (b.left, b).Resolve (rc);
2119 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2120 return ReducedExpression.Create (b.left, b).Resolve (rc);
2122 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2123 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2127 c = b.left as Constant;
2129 if (c.IsDefaultValue) {
2133 // (0 + expr) to expr
2134 // (false | bool?) to bool?
2136 if (b.oper == Operator.Addition ||
2137 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2138 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2139 return ReducedExpression.Create (b.right, b).Resolve (rc);
2143 // Optimizes (false && expr) to false
2145 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2146 // No rhs side-effects
2147 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2148 return ReducedExpression.Create (c, b);
2152 // Optimizes (0 & value) to 0
2154 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2155 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2156 return ReducedExpression.Create (side_effect, b);
2160 // Optimizes (true & bool?) to bool?
2162 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2163 return ReducedExpression.Create (b.right, b).Resolve (rc);
2167 // Optimizes (true || expr) to true
2169 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2170 // No rhs side-effects
2171 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2172 return ReducedExpression.Create (c, b);
2176 if (b.oper == Operator.Multiply && c.IsOneInteger)
2177 return ReducedExpression.Create (b.right, b).Resolve (rc);
2181 var lifted = new Nullable.LiftedBinaryOperator (b);
2183 TypeSpec ltype, rtype;
2184 if (b.left.Type.IsNullableType) {
2185 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2186 ltype = left_unwrap;
2191 if (b.right.Type.IsNullableType) {
2192 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2193 rtype = right_unwrap;
2198 lifted.Left = b.left.IsNull ?
2200 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2202 lifted.Right = b.right.IsNull ?
2204 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2206 return lifted.Resolve (rc);
2209 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2210 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2215 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2218 // We are dealing with primitive types only
2220 return left == ltype && ltype == rtype;
2223 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2226 if (left == lexpr.Type && right == rexpr.Type)
2229 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2230 Convert.ImplicitConversionExists (ec, rexpr, right);
2233 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2235 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2236 return best_operator;
2238 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2242 if (left != null && best_operator.left != null) {
2243 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2247 // When second argument is same as the first one, the result is same
2249 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2250 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2253 if (result == 0 || result > 2)
2256 return result == 1 ? best_operator : this;
2260 sealed class PredefinedStringOperator : PredefinedOperator
2262 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2263 : base (type, type, op_mask, retType)
2267 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2268 : base (ltype, rtype, op_mask, retType)
2272 public override Expression ConvertResult (ResolveContext ec, Binary b)
2275 // Use original expression for nullable arguments
2277 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2279 b.left = unwrap.Original;
2281 unwrap = b.right as Nullable.Unwrap;
2283 b.right = unwrap.Original;
2285 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2286 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2289 // Start a new concat expression using converted expression
2291 return StringConcat.Create (ec, b.left, b.right, b.loc);
2295 sealed class PredefinedEqualityOperator : PredefinedOperator
2297 MethodSpec equal_method, inequal_method;
2299 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
2300 : base (arg, arg, Operator.EqualityMask, retType)
2304 public override Expression ConvertResult (ResolveContext ec, Binary b)
2306 b.type = ReturnType;
2308 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2309 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2311 Arguments args = new Arguments (2);
2312 args.Add (new Argument (b.left));
2313 args.Add (new Argument (b.right));
2316 if (b.oper == Operator.Equality) {
2317 if (equal_method == null) {
2318 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2319 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2320 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2321 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2323 throw new NotImplementedException (left.GetSignatureForError ());
2326 method = equal_method;
2328 if (inequal_method == null) {
2329 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2330 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2331 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2332 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2334 throw new NotImplementedException (left.GetSignatureForError ());
2337 method = inequal_method;
2340 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2344 class PredefinedPointerOperator : PredefinedOperator
2346 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2347 : base (ltype, rtype, op_mask)
2351 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2352 : base (ltype, rtype, op_mask, retType)
2356 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2357 : base (type, op_mask, return_type)
2361 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2364 if (!lexpr.Type.IsPointer)
2367 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2371 if (right == null) {
2372 if (!rexpr.Type.IsPointer)
2375 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2382 public override Expression ConvertResult (ResolveContext ec, Binary b)
2385 b.left = EmptyCast.Create (b.left, left);
2386 } else if (right != null) {
2387 b.right = EmptyCast.Create (b.right, right);
2390 TypeSpec r_type = ReturnType;
2391 Expression left_arg, right_arg;
2392 if (r_type == null) {
2395 right_arg = b.right;
2396 r_type = b.left.Type;
2400 r_type = b.right.Type;
2404 right_arg = b.right;
2407 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2412 public enum Operator {
2413 Multiply = 0 | ArithmeticMask,
2414 Division = 1 | ArithmeticMask,
2415 Modulus = 2 | ArithmeticMask,
2416 Addition = 3 | ArithmeticMask | AdditionMask,
2417 Subtraction = 4 | ArithmeticMask | SubtractionMask,
2419 LeftShift = 5 | ShiftMask,
2420 RightShift = 6 | ShiftMask,
2422 LessThan = 7 | ComparisonMask | RelationalMask,
2423 GreaterThan = 8 | ComparisonMask | RelationalMask,
2424 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2425 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2426 Equality = 11 | ComparisonMask | EqualityMask,
2427 Inequality = 12 | ComparisonMask | EqualityMask,
2429 BitwiseAnd = 13 | BitwiseMask,
2430 ExclusiveOr = 14 | BitwiseMask,
2431 BitwiseOr = 15 | BitwiseMask,
2433 LogicalAnd = 16 | LogicalMask,
2434 LogicalOr = 17 | LogicalMask,
2439 ValuesOnlyMask = ArithmeticMask - 1,
2440 ArithmeticMask = 1 << 5,
2442 ComparisonMask = 1 << 7,
2443 EqualityMask = 1 << 8,
2444 BitwiseMask = 1 << 9,
2445 LogicalMask = 1 << 10,
2446 AdditionMask = 1 << 11,
2447 SubtractionMask = 1 << 12,
2448 RelationalMask = 1 << 13,
2450 DecomposedMask = 1 << 19,
2451 NullableMask = 1 << 20,
2461 readonly Operator oper;
2462 Expression left, right;
2464 ConvCast.Mode enum_conversion;
2466 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
2467 : this (oper, left, right)
2470 state |= State.Compound;
2473 public Binary (Operator oper, Expression left, Expression right)
2478 this.loc = left.Location;
2483 public bool IsCompound {
2485 return (state & State.Compound) != 0;
2489 public Operator Oper {
2495 public Expression Left {
2501 public Expression Right {
2507 public override Location StartLocation {
2509 return left.StartLocation;
2516 /// Returns a stringified representation of the Operator
2518 string OperName (Operator oper)
2522 case Operator.Multiply:
2525 case Operator.Division:
2528 case Operator.Modulus:
2531 case Operator.Addition:
2534 case Operator.Subtraction:
2537 case Operator.LeftShift:
2540 case Operator.RightShift:
2543 case Operator.LessThan:
2546 case Operator.GreaterThan:
2549 case Operator.LessThanOrEqual:
2552 case Operator.GreaterThanOrEqual:
2555 case Operator.Equality:
2558 case Operator.Inequality:
2561 case Operator.BitwiseAnd:
2564 case Operator.BitwiseOr:
2567 case Operator.ExclusiveOr:
2570 case Operator.LogicalOr:
2573 case Operator.LogicalAnd:
2577 s = oper.ToString ();
2587 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2589 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2592 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2594 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
2598 l = left.Type.GetSignatureForError ();
2599 r = right.Type.GetSignatureForError ();
2601 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2605 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2607 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2610 public override void FlowAnalysis (FlowAnalysisContext fc)
2612 if ((oper & Operator.LogicalMask) == 0) {
2613 var fc_ontrue = fc.DefiniteAssignmentOnTrue;
2614 var fc_onfalse = fc.DefiniteAssignmentOnFalse;
2615 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
2616 left.FlowAnalysis (fc);
2617 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
2618 right.FlowAnalysis (fc);
2619 fc.DefiniteAssignmentOnTrue = fc_ontrue;
2620 fc.DefiniteAssignmentOnFalse = fc_onfalse;
2625 // Optimized version when on-true/on-false data are not needed
2627 bool set_on_true_false;
2628 if (fc.DefiniteAssignmentOnTrue == null && fc.DefiniteAssignmentOnFalse == null) {
2629 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
2630 set_on_true_false = false;
2632 set_on_true_false = true;
2635 left.FlowAnalysis (fc);
2636 var left_fc = fc.DefiniteAssignment;
2637 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
2638 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
2640 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
2641 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
2642 right.FlowAnalysis (fc);
2643 fc.DefiniteAssignment = left_fc;
2645 if (!set_on_true_false) {
2646 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = null;
2650 if (oper == Operator.LogicalOr) {
2651 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue);
2652 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
2654 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
2655 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet (left_fc_onfalse);
2660 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2662 string GetOperatorExpressionTypeName ()
2665 case Operator.Addition:
2666 return IsCompound ? "AddAssign" : "Add";
2667 case Operator.BitwiseAnd:
2668 return IsCompound ? "AndAssign" : "And";
2669 case Operator.BitwiseOr:
2670 return IsCompound ? "OrAssign" : "Or";
2671 case Operator.Division:
2672 return IsCompound ? "DivideAssign" : "Divide";
2673 case Operator.ExclusiveOr:
2674 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2675 case Operator.Equality:
2677 case Operator.GreaterThan:
2678 return "GreaterThan";
2679 case Operator.GreaterThanOrEqual:
2680 return "GreaterThanOrEqual";
2681 case Operator.Inequality:
2683 case Operator.LeftShift:
2684 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2685 case Operator.LessThan:
2687 case Operator.LessThanOrEqual:
2688 return "LessThanOrEqual";
2689 case Operator.LogicalAnd:
2691 case Operator.LogicalOr:
2693 case Operator.Modulus:
2694 return IsCompound ? "ModuloAssign" : "Modulo";
2695 case Operator.Multiply:
2696 return IsCompound ? "MultiplyAssign" : "Multiply";
2697 case Operator.RightShift:
2698 return IsCompound ? "RightShiftAssign" : "RightShift";
2699 case Operator.Subtraction:
2700 return IsCompound ? "SubtractAssign" : "Subtract";
2702 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2706 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2709 case Operator.Addition:
2710 return CSharp.Operator.OpType.Addition;
2711 case Operator.BitwiseAnd:
2712 case Operator.LogicalAnd:
2713 return CSharp.Operator.OpType.BitwiseAnd;
2714 case Operator.BitwiseOr:
2715 case Operator.LogicalOr:
2716 return CSharp.Operator.OpType.BitwiseOr;
2717 case Operator.Division:
2718 return CSharp.Operator.OpType.Division;
2719 case Operator.Equality:
2720 return CSharp.Operator.OpType.Equality;
2721 case Operator.ExclusiveOr:
2722 return CSharp.Operator.OpType.ExclusiveOr;
2723 case Operator.GreaterThan:
2724 return CSharp.Operator.OpType.GreaterThan;
2725 case Operator.GreaterThanOrEqual:
2726 return CSharp.Operator.OpType.GreaterThanOrEqual;
2727 case Operator.Inequality:
2728 return CSharp.Operator.OpType.Inequality;
2729 case Operator.LeftShift:
2730 return CSharp.Operator.OpType.LeftShift;
2731 case Operator.LessThan:
2732 return CSharp.Operator.OpType.LessThan;
2733 case Operator.LessThanOrEqual:
2734 return CSharp.Operator.OpType.LessThanOrEqual;
2735 case Operator.Modulus:
2736 return CSharp.Operator.OpType.Modulus;
2737 case Operator.Multiply:
2738 return CSharp.Operator.OpType.Multiply;
2739 case Operator.RightShift:
2740 return CSharp.Operator.OpType.RightShift;
2741 case Operator.Subtraction:
2742 return CSharp.Operator.OpType.Subtraction;
2744 throw new InternalErrorException (op.ToString ());
2748 public override bool ContainsEmitWithAwait ()
2750 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2753 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2758 case Operator.Multiply:
2759 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2760 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2761 opcode = OpCodes.Mul_Ovf;
2762 else if (!IsFloat (l))
2763 opcode = OpCodes.Mul_Ovf_Un;
2765 opcode = OpCodes.Mul;
2767 opcode = OpCodes.Mul;
2771 case Operator.Division:
2773 opcode = OpCodes.Div_Un;
2775 opcode = OpCodes.Div;
2778 case Operator.Modulus:
2780 opcode = OpCodes.Rem_Un;
2782 opcode = OpCodes.Rem;
2785 case Operator.Addition:
2786 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2787 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2788 opcode = OpCodes.Add_Ovf;
2789 else if (!IsFloat (l))
2790 opcode = OpCodes.Add_Ovf_Un;
2792 opcode = OpCodes.Add;
2794 opcode = OpCodes.Add;
2797 case Operator.Subtraction:
2798 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2799 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2800 opcode = OpCodes.Sub_Ovf;
2801 else if (!IsFloat (l))
2802 opcode = OpCodes.Sub_Ovf_Un;
2804 opcode = OpCodes.Sub;
2806 opcode = OpCodes.Sub;
2809 case Operator.RightShift:
2810 if (!(right is IntConstant)) {
2811 ec.EmitInt (GetShiftMask (l));
2812 ec.Emit (OpCodes.And);
2816 opcode = OpCodes.Shr_Un;
2818 opcode = OpCodes.Shr;
2821 case Operator.LeftShift:
2822 if (!(right is IntConstant)) {
2823 ec.EmitInt (GetShiftMask (l));
2824 ec.Emit (OpCodes.And);
2827 opcode = OpCodes.Shl;
2830 case Operator.Equality:
2831 opcode = OpCodes.Ceq;
2834 case Operator.Inequality:
2835 ec.Emit (OpCodes.Ceq);
2838 opcode = OpCodes.Ceq;
2841 case Operator.LessThan:
2843 opcode = OpCodes.Clt_Un;
2845 opcode = OpCodes.Clt;
2848 case Operator.GreaterThan:
2850 opcode = OpCodes.Cgt_Un;
2852 opcode = OpCodes.Cgt;
2855 case Operator.LessThanOrEqual:
2856 if (IsUnsigned (l) || IsFloat (l))
2857 ec.Emit (OpCodes.Cgt_Un);
2859 ec.Emit (OpCodes.Cgt);
2862 opcode = OpCodes.Ceq;
2865 case Operator.GreaterThanOrEqual:
2866 if (IsUnsigned (l) || IsFloat (l))
2867 ec.Emit (OpCodes.Clt_Un);
2869 ec.Emit (OpCodes.Clt);
2873 opcode = OpCodes.Ceq;
2876 case Operator.BitwiseOr:
2877 opcode = OpCodes.Or;
2880 case Operator.BitwiseAnd:
2881 opcode = OpCodes.And;
2884 case Operator.ExclusiveOr:
2885 opcode = OpCodes.Xor;
2889 throw new InternalErrorException (oper.ToString ());
2895 static int GetShiftMask (TypeSpec type)
2897 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2900 static bool IsUnsigned (TypeSpec t)
2902 switch (t.BuiltinType) {
2903 case BuiltinTypeSpec.Type.Char:
2904 case BuiltinTypeSpec.Type.UInt:
2905 case BuiltinTypeSpec.Type.ULong:
2906 case BuiltinTypeSpec.Type.UShort:
2907 case BuiltinTypeSpec.Type.Byte:
2914 static bool IsFloat (TypeSpec t)
2916 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2919 public Expression ResolveOperator (ResolveContext rc)
2921 eclass = ExprClass.Value;
2923 TypeSpec l = left.Type;
2924 TypeSpec r = right.Type;
2926 bool primitives_only = false;
2929 // Handles predefined primitive types
2931 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2932 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2933 if ((oper & Operator.ShiftMask) == 0) {
2934 if (!DoBinaryOperatorPromotion (rc))
2937 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2941 if (l.IsPointer || r.IsPointer)
2942 return ResolveOperatorPointer (rc, l, r);
2945 expr = ResolveUserOperator (rc, left, right);
2950 bool lenum = l.IsEnum;
2951 bool renum = r.IsEnum;
2952 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2956 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2957 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2962 if ((oper & Operator.BitwiseMask) != 0) {
2963 expr = EmptyCast.Create (expr, type);
2964 AddEnumResultCast (type);
2966 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2967 expr = OptimizeAndOperation (expr);
2971 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
2972 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
2975 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2976 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2980 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2983 // We cannot break here there is also Enum + String possible match
2984 // which is not ambiguous with predefined enum operators
2987 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
2988 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
2992 } else if (l.IsDelegate || r.IsDelegate) {
2996 expr = ResolveOperatorDelegate (rc, l, r);
2998 // TODO: Can this be ambiguous
3006 // Equality operators are more complicated
3008 if ((oper & Operator.EqualityMask) != 0) {
3009 return ResolveEquality (rc, l, r, primitives_only);
3012 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3016 if (primitives_only)
3020 // Lifted operators have lower priority
3022 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3025 static bool IsEnumOrNullableEnum (TypeSpec type)
3027 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3031 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3032 // if 'left' is not an enumeration constant, create one from the type of 'right'
3033 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3036 case Operator.BitwiseOr:
3037 case Operator.BitwiseAnd:
3038 case Operator.ExclusiveOr:
3039 case Operator.Equality:
3040 case Operator.Inequality:
3041 case Operator.LessThan:
3042 case Operator.LessThanOrEqual:
3043 case Operator.GreaterThan:
3044 case Operator.GreaterThanOrEqual:
3045 if (left.Type.IsEnum)
3048 if (left.IsZeroInteger)
3049 return left.Reduce (ec, right.Type);
3053 case Operator.Addition:
3054 case Operator.Subtraction:
3057 case Operator.Multiply:
3058 case Operator.Division:
3059 case Operator.Modulus:
3060 case Operator.LeftShift:
3061 case Operator.RightShift:
3062 if (right.Type.IsEnum || left.Type.IsEnum)
3071 // The `|' operator used on types which were extended is dangerous
3073 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3075 OpcodeCast lcast = left as OpcodeCast;
3076 if (lcast != null) {
3077 if (IsUnsigned (lcast.UnderlyingType))
3081 OpcodeCast rcast = right as OpcodeCast;
3082 if (rcast != null) {
3083 if (IsUnsigned (rcast.UnderlyingType))
3087 if (lcast == null && rcast == null)
3090 // FIXME: consider constants
3092 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3093 ec.Report.Warning (675, 3, loc,
3094 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3095 ltype.GetSignatureForError ());
3098 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3100 return new PredefinedOperator[] {
3102 // Pointer arithmetic:
3104 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3105 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3106 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3107 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3109 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3110 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3111 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3112 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3115 // T* operator + (int y, T* x);
3116 // T* operator + (uint y, T *x);
3117 // T* operator + (long y, T *x);
3118 // T* operator + (ulong y, T *x);
3120 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3121 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3122 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3123 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3126 // long operator - (T* x, T *y)
3128 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3132 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3134 TypeSpec bool_type = types.Bool;
3137 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3138 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3139 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3140 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3141 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3142 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3143 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3145 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3146 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3147 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3148 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3149 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3150 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3151 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3153 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3154 // Remaining string operators are in lifted tables
3156 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3158 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3159 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3160 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3164 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3166 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3167 if (nullable == null)
3168 return new PredefinedOperator [0];
3170 var types = module.Compiler.BuiltinTypes;
3171 var bool_type = types.Bool;
3173 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3174 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3175 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3176 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3177 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3178 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3179 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3180 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3183 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3184 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3185 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3186 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3187 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3188 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3189 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3191 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3192 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3193 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3194 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3195 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3196 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3197 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3199 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3201 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3202 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3203 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3206 // Not strictly lifted but need to be in second group otherwise expressions like
3207 // int + null would resolve to +(object, string) instead of +(int?, int?)
3209 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3210 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3215 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3217 TypeSpec bool_type = types.Bool;
3220 new PredefinedEqualityOperator (types.String, bool_type),
3221 new PredefinedEqualityOperator (types.Delegate, bool_type),
3222 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3223 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3224 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3225 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3226 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3227 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3228 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3229 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3233 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3235 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3237 if (nullable == null)
3238 return new PredefinedOperator [0];
3240 var types = module.Compiler.BuiltinTypes;
3241 var bool_type = types.Bool;
3242 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3243 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3244 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3245 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3246 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3247 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3248 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3249 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3252 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3253 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3254 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3255 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3256 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3257 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3258 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3259 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3264 // 7.2.6.2 Binary numeric promotions
3266 bool DoBinaryOperatorPromotion (ResolveContext rc)
3268 TypeSpec ltype = left.Type;
3269 if (ltype.IsNullableType) {
3270 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3274 // This is numeric promotion code only
3276 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3279 TypeSpec rtype = right.Type;
3280 if (rtype.IsNullableType) {
3281 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3284 var lb = ltype.BuiltinType;
3285 var rb = rtype.BuiltinType;
3289 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3290 type = rc.BuiltinTypes.Decimal;
3291 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3292 type = rc.BuiltinTypes.Double;
3293 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3294 type = rc.BuiltinTypes.Float;
3295 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3296 type = rc.BuiltinTypes.ULong;
3298 if (IsSignedType (lb)) {
3299 expr = ConvertSignedConstant (left, type);
3303 } else if (IsSignedType (rb)) {
3304 expr = ConvertSignedConstant (right, type);
3310 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3311 type = rc.BuiltinTypes.Long;
3312 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3313 type = rc.BuiltinTypes.UInt;
3315 if (IsSignedType (lb)) {
3316 expr = ConvertSignedConstant (left, type);
3318 type = rc.BuiltinTypes.Long;
3319 } else if (IsSignedType (rb)) {
3320 expr = ConvertSignedConstant (right, type);
3322 type = rc.BuiltinTypes.Long;
3325 type = rc.BuiltinTypes.Int;
3328 if (ltype != type) {
3329 expr = PromoteExpression (rc, left, type);
3336 if (rtype != type) {
3337 expr = PromoteExpression (rc, right, type);
3347 static bool IsSignedType (BuiltinTypeSpec.Type type)
3350 case BuiltinTypeSpec.Type.Int:
3351 case BuiltinTypeSpec.Type.Short:
3352 case BuiltinTypeSpec.Type.SByte:
3353 case BuiltinTypeSpec.Type.Long:
3360 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3362 var c = expr as Constant;
3366 return c.ConvertImplicitly (type);
3369 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3371 if (expr.Type.IsNullableType) {
3372 return Convert.ImplicitConversionStandard (rc, expr,
3373 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3376 var c = expr as Constant;
3378 return c.ConvertImplicitly (type);
3380 return Convert.ImplicitNumericConversion (expr, type);
3383 protected override Expression DoResolve (ResolveContext ec)
3388 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3389 left = ((ParenthesizedExpression) left).Expr;
3390 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3394 if (left.eclass == ExprClass.Type) {
3395 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3399 left = left.Resolve (ec);
3404 right = right.Resolve (ec);
3408 Constant lc = left as Constant;
3409 Constant rc = right as Constant;
3411 // The conversion rules are ignored in enum context but why
3412 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3413 lc = EnumLiftUp (ec, lc, rc);
3415 rc = EnumLiftUp (ec, rc, lc);
3418 if (rc != null && lc != null) {
3419 int prev_e = ec.Report.Errors;
3420 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3421 if (e != null || ec.Report.Errors != prev_e)
3425 // Comparison warnings
3426 if ((oper & Operator.ComparisonMask) != 0) {
3427 if (left.Equals (right)) {
3428 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3430 CheckOutOfRangeComparison (ec, lc, right.Type);
3431 CheckOutOfRangeComparison (ec, rc, left.Type);
3434 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3435 return DoResolveDynamic (ec);
3437 return DoResolveCore (ec, left, right);
3440 Expression DoResolveDynamic (ResolveContext rc)
3443 var rt = right.Type;
3444 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3445 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3446 Error_OperatorCannotBeApplied (rc, left, right);
3453 // Special handling for logical boolean operators which require rhs not to be
3454 // evaluated based on lhs value
3456 if ((oper & Operator.LogicalMask) != 0) {
3457 Expression cond_left, cond_right, expr;
3459 args = new Arguments (2);
3461 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3462 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3464 var cond_args = new Arguments (1);
3465 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3468 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3469 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3471 left = temp.CreateReferenceExpression (rc, loc);
3472 if (oper == Operator.LogicalAnd) {
3473 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3476 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3480 args.Add (new Argument (left));
3481 args.Add (new Argument (right));
3482 cond_right = new DynamicExpressionStatement (this, args, loc);
3484 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3486 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3487 args.Add (new Argument (right));
3488 right = new DynamicExpressionStatement (this, args, loc);
3491 // bool && dynamic => (temp = left) ? temp && right : temp;
3492 // bool || dynamic => (temp = left) ? temp : temp || right;
3494 if (oper == Operator.LogicalAnd) {
3496 cond_right = temp.CreateReferenceExpression (rc, loc);
3498 cond_left = temp.CreateReferenceExpression (rc, loc);
3502 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3505 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3508 args = new Arguments (2);
3509 args.Add (new Argument (left));
3510 args.Add (new Argument (right));
3511 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3514 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3516 Expression expr = ResolveOperator (ec);
3518 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3520 if (left == null || right == null)
3521 throw new InternalErrorException ("Invalid conversion");
3523 if (oper == Operator.BitwiseOr)
3524 CheckBitwiseOrOnSignExtended (ec);
3529 public override SLE.Expression MakeExpression (BuilderContext ctx)
3531 return MakeExpression (ctx, left, right);
3534 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3536 var le = left.MakeExpression (ctx);
3537 var re = right.MakeExpression (ctx);
3538 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3541 case Operator.Addition:
3542 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3543 case Operator.BitwiseAnd:
3544 return SLE.Expression.And (le, re);
3545 case Operator.BitwiseOr:
3546 return SLE.Expression.Or (le, re);
3547 case Operator.Division:
3548 return SLE.Expression.Divide (le, re);
3549 case Operator.Equality:
3550 return SLE.Expression.Equal (le, re);
3551 case Operator.ExclusiveOr:
3552 return SLE.Expression.ExclusiveOr (le, re);
3553 case Operator.GreaterThan:
3554 return SLE.Expression.GreaterThan (le, re);
3555 case Operator.GreaterThanOrEqual:
3556 return SLE.Expression.GreaterThanOrEqual (le, re);
3557 case Operator.Inequality:
3558 return SLE.Expression.NotEqual (le, re);
3559 case Operator.LeftShift:
3560 return SLE.Expression.LeftShift (le, re);
3561 case Operator.LessThan:
3562 return SLE.Expression.LessThan (le, re);
3563 case Operator.LessThanOrEqual:
3564 return SLE.Expression.LessThanOrEqual (le, re);
3565 case Operator.LogicalAnd:
3566 return SLE.Expression.AndAlso (le, re);
3567 case Operator.LogicalOr:
3568 return SLE.Expression.OrElse (le, re);
3569 case Operator.Modulus:
3570 return SLE.Expression.Modulo (le, re);
3571 case Operator.Multiply:
3572 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3573 case Operator.RightShift:
3574 return SLE.Expression.RightShift (le, re);
3575 case Operator.Subtraction:
3576 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3578 throw new NotImplementedException (oper.ToString ());
3583 // D operator + (D x, D y)
3584 // D operator - (D x, D y)
3586 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3588 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3590 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3591 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3596 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3597 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3607 MethodSpec method = null;
3608 Arguments args = new Arguments (2);
3609 args.Add (new Argument (left));
3610 args.Add (new Argument (right));
3612 if (oper == Operator.Addition) {
3613 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3614 } else if (oper == Operator.Subtraction) {
3615 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3619 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3621 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3622 return new ClassCast (expr, l);
3626 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3628 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3631 // bool operator == (E x, E y);
3632 // bool operator != (E x, E y);
3633 // bool operator < (E x, E y);
3634 // bool operator > (E x, E y);
3635 // bool operator <= (E x, E y);
3636 // bool operator >= (E x, E y);
3638 // E operator & (E x, E y);
3639 // E operator | (E x, E y);
3640 // E operator ^ (E x, E y);
3643 if ((oper & Operator.ComparisonMask) != 0) {
3644 type = rc.BuiltinTypes.Bool;
3650 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3656 if (ltype == rtype) {
3660 var lifted = new Nullable.LiftedBinaryOperator (this);
3662 lifted.Right = right;
3663 return lifted.Resolve (rc);
3666 if (renum && !ltype.IsNullableType) {
3667 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3672 } else if (lenum && !rtype.IsNullableType) {
3673 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3681 // Now try lifted version of predefined operator
3683 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3684 if (nullable_type != null) {
3685 if (renum && !ltype.IsNullableType) {
3686 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3688 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3691 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3694 if ((oper & Operator.BitwiseMask) != 0)
3698 if ((oper & Operator.BitwiseMask) != 0)
3699 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3701 return CreateLiftedValueTypeResult (rc, rtype);
3705 var lifted = new Nullable.LiftedBinaryOperator (this);
3707 lifted.Right = right;
3708 return lifted.Resolve (rc);
3710 } else if (lenum && !rtype.IsNullableType) {
3711 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3713 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3716 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3719 if ((oper & Operator.BitwiseMask) != 0)
3723 if ((oper & Operator.BitwiseMask) != 0)
3724 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3726 return CreateLiftedValueTypeResult (rc, ltype);
3730 var lifted = new Nullable.LiftedBinaryOperator (this);
3732 lifted.Right = expr;
3733 return lifted.Resolve (rc);
3735 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3737 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3738 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3740 if ((oper & Operator.RelationalMask) != 0)
3741 return CreateLiftedValueTypeResult (rc, rtype);
3743 if ((oper & Operator.BitwiseMask) != 0)
3744 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3746 // Equality operators are valid between E? and null
3749 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3755 var lifted = new Nullable.LiftedBinaryOperator (this);
3757 lifted.Right = right;
3758 return lifted.Resolve (rc);
3760 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3762 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3763 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3765 if ((oper & Operator.RelationalMask) != 0)
3766 return CreateLiftedValueTypeResult (rc, ltype);
3768 if ((oper & Operator.BitwiseMask) != 0)
3769 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3771 // Equality operators are valid between E? and null
3774 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3780 var lifted = new Nullable.LiftedBinaryOperator (this);
3782 lifted.Right = expr;
3783 return lifted.Resolve (rc);
3791 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
3793 TypeSpec underlying_type;
3794 if (expr.Type.IsNullableType) {
3795 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3797 underlying_type = EnumSpec.GetUnderlyingType (nt);
3799 underlying_type = nt;
3800 } else if (expr.Type.IsEnum) {
3801 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3803 underlying_type = expr.Type;
3806 switch (underlying_type.BuiltinType) {
3807 case BuiltinTypeSpec.Type.SByte:
3808 case BuiltinTypeSpec.Type.Byte:
3809 case BuiltinTypeSpec.Type.Short:
3810 case BuiltinTypeSpec.Type.UShort:
3811 underlying_type = rc.BuiltinTypes.Int;
3815 if (expr.Type.IsNullableType || liftType)
3816 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3818 if (expr.Type == underlying_type)
3821 return EmptyCast.Create (expr, underlying_type);
3824 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3827 // U operator - (E e, E f)
3828 // E operator - (E e, U x) // Internal decomposition operator
3829 // E operator - (U x, E e) // Internal decomposition operator
3831 // E operator + (E e, U x)
3832 // E operator + (U x, E e)
3841 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3847 if (!enum_type.IsNullableType) {
3848 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3850 if (oper == Operator.Subtraction)
3851 expr = ConvertEnumSubtractionResult (rc, expr);
3853 expr = ConvertEnumAdditionalResult (expr, enum_type);
3855 AddEnumResultCast (expr.Type);
3860 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3863 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3865 if (oper == Operator.Subtraction)
3866 expr = ConvertEnumSubtractionResult (rc, expr);
3868 expr = ConvertEnumAdditionalResult (expr, enum_type);
3870 AddEnumResultCast (expr.Type);
3876 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3878 return EmptyCast.Create (expr, enumType);
3881 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3884 // Enumeration subtraction has different result type based on
3887 TypeSpec result_type;
3888 if (left.Type == right.Type) {
3889 var c = right as EnumConstant;
3890 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
3892 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3893 // E which is not what expressions E - 1 or 0 - E return
3895 result_type = left.Type;
3897 result_type = left.Type.IsNullableType ?
3898 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3899 EnumSpec.GetUnderlyingType (left.Type);
3902 if (IsEnumOrNullableEnum (left.Type)) {
3903 result_type = left.Type;
3905 result_type = right.Type;
3908 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3909 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3912 return EmptyCast.Create (expr, result_type);
3915 void AddEnumResultCast (TypeSpec type)
3917 if (type.IsNullableType)
3918 type = Nullable.NullableInfo.GetUnderlyingType (type);
3921 type = EnumSpec.GetUnderlyingType (type);
3923 switch (type.BuiltinType) {
3924 case BuiltinTypeSpec.Type.SByte:
3925 enum_conversion = ConvCast.Mode.I4_I1;
3927 case BuiltinTypeSpec.Type.Byte:
3928 enum_conversion = ConvCast.Mode.I4_U1;
3930 case BuiltinTypeSpec.Type.Short:
3931 enum_conversion = ConvCast.Mode.I4_I2;
3933 case BuiltinTypeSpec.Type.UShort:
3934 enum_conversion = ConvCast.Mode.I4_U2;
3940 // Equality operators rules
3942 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3945 type = ec.BuiltinTypes.Bool;
3946 bool no_arg_conv = false;
3948 if (!primitives_only) {
3951 // a, Both operands are reference-type values or the value null
3952 // b, One operand is a value of type T where T is a type-parameter and
3953 // the other operand is the value null. Furthermore T does not have the
3954 // value type constraint
3956 // LAMESPEC: Very confusing details in the specification, basically any
3957 // reference like type-parameter is allowed
3959 var tparam_l = l as TypeParameterSpec;
3960 var tparam_r = r as TypeParameterSpec;
3961 if (tparam_l != null) {
3962 if (right is NullLiteral) {
3963 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3966 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3970 if (!tparam_l.IsReferenceType)
3973 l = tparam_l.GetEffectiveBase ();
3974 left = new BoxedCast (left, l);
3975 } else if (left is NullLiteral && tparam_r == null) {
3976 if (TypeSpec.IsReferenceType (r))
3979 if (r.Kind == MemberKind.InternalCompilerType)
3983 if (tparam_r != null) {
3984 if (left is NullLiteral) {
3985 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3988 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3992 if (!tparam_r.IsReferenceType)
3995 r = tparam_r.GetEffectiveBase ();
3996 right = new BoxedCast (right, r);
3997 } else if (right is NullLiteral) {
3998 if (TypeSpec.IsReferenceType (l))
4001 if (l.Kind == MemberKind.InternalCompilerType)
4006 // LAMESPEC: method groups can be compared when they convert to other side delegate
4009 if (right.eclass == ExprClass.MethodGroup) {
4010 result = Convert.ImplicitConversion (ec, right, l, loc);
4016 } else if (r.IsDelegate && l != r) {
4019 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4020 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4027 no_arg_conv = l == r && !l.IsStruct;
4032 // bool operator != (string a, string b)
4033 // bool operator == (string a, string b)
4035 // bool operator != (Delegate a, Delegate b)
4036 // bool operator == (Delegate a, Delegate b)
4038 // bool operator != (bool a, bool b)
4039 // bool operator == (bool a, bool b)
4041 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4042 // they implement an implicit conversion to any of types above. This does
4043 // not apply when both operands are of same reference type
4045 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4046 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4051 // Now try lifted version of predefined operators
4053 if (no_arg_conv && !l.IsNullableType) {
4055 // Optimizes cases which won't match
4058 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4064 // The == and != operators permit one operand to be a value of a nullable
4065 // type and the other to be the null literal, even if no predefined or user-defined
4066 // operator (in unlifted or lifted form) exists for the operation.
4068 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4069 var lifted = new Nullable.LiftedBinaryOperator (this);
4071 lifted.Right = right;
4072 return lifted.Resolve (ec);
4077 // bool operator != (object a, object b)
4078 // bool operator == (object a, object b)
4080 // An explicit reference conversion exists from the
4081 // type of either operand to the type of the other operand.
4084 // Optimize common path
4086 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4089 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4090 !Convert.ExplicitReferenceConversionExists (r, l))
4093 // Reject allowed explicit conversions like int->object
4094 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4097 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4098 ec.Report.Warning (253, 2, loc,
4099 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4100 l.GetSignatureForError ());
4102 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4103 ec.Report.Warning (252, 2, loc,
4104 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4105 r.GetSignatureForError ());
4111 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4114 // bool operator == (void* x, void* y);
4115 // bool operator != (void* x, void* y);
4116 // bool operator < (void* x, void* y);
4117 // bool operator > (void* x, void* y);
4118 // bool operator <= (void* x, void* y);
4119 // bool operator >= (void* x, void* y);
4121 if ((oper & Operator.ComparisonMask) != 0) {
4124 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4131 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4137 type = ec.BuiltinTypes.Bool;
4141 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4145 // Build-in operators method overloading
4147 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4149 PredefinedOperator best_operator = null;
4150 TypeSpec l = left.Type;
4151 TypeSpec r = right.Type;
4152 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4154 foreach (PredefinedOperator po in operators) {
4155 if ((po.OperatorsMask & oper_mask) == 0)
4158 if (primitives_only) {
4159 if (!po.IsPrimitiveApplicable (l, r))
4162 if (!po.IsApplicable (ec, left, right))
4166 if (best_operator == null) {
4168 if (primitives_only)
4174 best_operator = po.ResolveBetterOperator (ec, best_operator);
4176 if (best_operator == null) {
4177 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4178 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4185 if (best_operator == null)
4188 return best_operator.ConvertResult (ec, this);
4192 // Optimize & constant expressions with 0 value
4194 Expression OptimizeAndOperation (Expression expr)
4196 Constant rc = right as Constant;
4197 Constant lc = left as Constant;
4198 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4200 // The result is a constant with side-effect
4202 Constant side_effect = rc == null ?
4203 new SideEffectConstant (lc, right, loc) :
4204 new SideEffectConstant (rc, left, loc);
4206 return ReducedExpression.Create (side_effect, expr);
4213 // Value types can be compared with the null literal because of the lifting
4214 // language rules. However the result is always true or false.
4216 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4218 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4219 type = rc.BuiltinTypes.Bool;
4223 // FIXME: Handle side effect constants
4224 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4226 if ((Oper & Operator.EqualityMask) != 0) {
4227 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4228 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4230 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4231 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4238 // Performs user-operator overloading
4240 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4242 Expression oper_expr;
4244 var op = ConvertBinaryToUserOperator (oper);
4246 if (l.IsNullableType)
4247 l = Nullable.NullableInfo.GetUnderlyingType (l);
4249 if (r.IsNullableType)
4250 r = Nullable.NullableInfo.GetUnderlyingType (r);
4252 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4253 IList<MemberSpec> right_operators = null;
4256 right_operators = MemberCache.GetUserOperator (r, op, false);
4257 if (right_operators == null && left_operators == null)
4259 } else if (left_operators == null) {
4263 Arguments args = new Arguments (2);
4264 Argument larg = new Argument (left);
4266 Argument rarg = new Argument (right);
4270 // User-defined operator implementations always take precedence
4271 // over predefined operator implementations
4273 if (left_operators != null && right_operators != null) {
4274 left_operators = CombineUserOperators (left_operators, right_operators);
4275 } else if (right_operators != null) {
4276 left_operators = right_operators;
4279 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4280 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4282 var res = new OverloadResolver (left_operators, restr, loc);
4284 var oper_method = res.ResolveOperator (rc, ref args);
4285 if (oper_method == null) {
4287 // Logical && and || cannot be lifted
4289 if ((oper & Operator.LogicalMask) != 0)
4293 // Apply lifted user operators only for liftable types. Implicit conversion
4294 // to nullable types is not allowed
4296 if (!IsLiftedOperatorApplicable ())
4299 // TODO: Cache the result in module container
4300 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4301 if (lifted_methods == null)
4304 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4306 oper_method = res.ResolveOperator (rc, ref args);
4307 if (oper_method == null)
4310 MethodSpec best_original = null;
4311 foreach (MethodSpec ms in left_operators) {
4312 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4318 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4320 // Expression trees use lifted notation in this case
4322 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4323 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4326 var ptypes = best_original.Parameters.Types;
4328 if (left.IsNull || right.IsNull) {
4330 // The lifted operator produces the value false if one or both operands are null for
4331 // relational operators.
4333 if ((oper & Operator.ComparisonMask) != 0) {
4335 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4336 // because return type is actually bool
4338 // For some reason CSC does not report this warning for equality operators
4340 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4343 // The lifted operator produces a null value if one or both operands are null
4345 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4346 type = oper_method.ReturnType;
4347 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4351 type = oper_method.ReturnType;
4352 var lifted = new Nullable.LiftedBinaryOperator (this);
4353 lifted.UserOperator = best_original;
4355 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4356 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4359 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4360 lifted.UnwrapRight = new Nullable.Unwrap (right);
4363 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4364 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4366 return lifted.Resolve (rc);
4369 if ((oper & Operator.LogicalMask) != 0) {
4370 // TODO: CreateExpressionTree is allocated every time
4371 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4372 oper == Operator.LogicalAnd, loc).Resolve (rc);
4374 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4377 this.left = larg.Expr;
4378 this.right = rarg.Expr;
4383 bool IsLiftedOperatorApplicable ()
4385 if (left.Type.IsNullableType) {
4386 if ((oper & Operator.EqualityMask) != 0)
4387 return !right.IsNull;
4392 if (right.Type.IsNullableType) {
4393 if ((oper & Operator.EqualityMask) != 0)
4394 return !left.IsNull;
4399 if (TypeSpec.IsValueType (left.Type))
4400 return right.IsNull;
4402 if (TypeSpec.IsValueType (right.Type))
4408 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4410 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4411 if (nullable_type == null)
4415 // Lifted operators permit predefined and user-defined operators that operate
4416 // on non-nullable value types to also be used with nullable forms of those types.
4417 // Lifted operators are constructed from predefined and user-defined operators
4418 // that meet certain requirements
4420 List<MemberSpec> lifted = null;
4421 foreach (MethodSpec oper in operators) {
4423 if ((Oper & Operator.ComparisonMask) != 0) {
4425 // Result type must be of type bool for lifted comparison operators
4427 rt = oper.ReturnType;
4428 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4431 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4437 var ptypes = oper.Parameters.Types;
4438 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4442 // LAMESPEC: I am not sure why but for equality operators to be lifted
4443 // both types have to match
4445 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4449 lifted = new List<MemberSpec> ();
4452 // The lifted form is constructed by adding a single ? modifier to each operand and
4453 // result type except for comparison operators where return type is bool
4456 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4458 var parameters = ParametersCompiled.CreateFullyResolved (
4459 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4460 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4462 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4463 rt, parameters, oper.Modifiers);
4465 lifted.Add (lifted_op);
4472 // Merge two sets of user operators into one, they are mostly distinguish
4473 // except when they share base type and it contains an operator
4475 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4477 var combined = new List<MemberSpec> (left.Count + right.Count);
4478 combined.AddRange (left);
4479 foreach (var r in right) {
4481 foreach (var l in left) {
4482 if (l.DeclaringType == r.DeclaringType) {
4495 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4497 if (c is IntegralConstant || c is CharConstant) {
4499 c.ConvertExplicitly (true, type);
4500 } catch (OverflowException) {
4501 ec.Report.Warning (652, 2, loc,
4502 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4503 type.GetSignatureForError ());
4509 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4510 /// context of a conditional bool expression. This function will return
4511 /// false if it is was possible to use EmitBranchable, or true if it was.
4513 /// The expression's code is generated, and we will generate a branch to `target'
4514 /// if the resulting expression value is equal to isTrue
4516 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4518 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4519 left = left.EmitToField (ec);
4521 if ((oper & Operator.LogicalMask) == 0) {
4522 right = right.EmitToField (ec);
4527 // This is more complicated than it looks, but its just to avoid
4528 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4529 // but on top of that we want for == and != to use a special path
4530 // if we are comparing against null
4532 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4533 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4536 // put the constant on the rhs, for simplicity
4538 if (left is Constant) {
4539 Expression swap = right;
4545 // brtrue/brfalse works with native int only
4547 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4548 left.EmitBranchable (ec, target, my_on_true);
4551 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4552 // right is a boolean, and it's not 'false' => it is 'true'
4553 left.EmitBranchable (ec, target, !my_on_true);
4557 } else if (oper == Operator.LogicalAnd) {
4560 Label tests_end = ec.DefineLabel ();
4562 left.EmitBranchable (ec, tests_end, false);
4563 right.EmitBranchable (ec, target, true);
4564 ec.MarkLabel (tests_end);
4567 // This optimizes code like this
4568 // if (true && i > 4)
4570 if (!(left is Constant))
4571 left.EmitBranchable (ec, target, false);
4573 if (!(right is Constant))
4574 right.EmitBranchable (ec, target, false);
4579 } else if (oper == Operator.LogicalOr){
4581 left.EmitBranchable (ec, target, true);
4582 right.EmitBranchable (ec, target, true);
4585 Label tests_end = ec.DefineLabel ();
4586 left.EmitBranchable (ec, tests_end, true);
4587 right.EmitBranchable (ec, target, false);
4588 ec.MarkLabel (tests_end);
4593 } else if ((oper & Operator.ComparisonMask) == 0) {
4594 base.EmitBranchable (ec, target, on_true);
4601 TypeSpec t = left.Type;
4602 bool is_float = IsFloat (t);
4603 bool is_unsigned = is_float || IsUnsigned (t);
4606 case Operator.Equality:
4608 ec.Emit (OpCodes.Beq, target);
4610 ec.Emit (OpCodes.Bne_Un, target);
4613 case Operator.Inequality:
4615 ec.Emit (OpCodes.Bne_Un, target);
4617 ec.Emit (OpCodes.Beq, target);
4620 case Operator.LessThan:
4622 if (is_unsigned && !is_float)
4623 ec.Emit (OpCodes.Blt_Un, target);
4625 ec.Emit (OpCodes.Blt, target);
4628 ec.Emit (OpCodes.Bge_Un, target);
4630 ec.Emit (OpCodes.Bge, target);
4633 case Operator.GreaterThan:
4635 if (is_unsigned && !is_float)
4636 ec.Emit (OpCodes.Bgt_Un, target);
4638 ec.Emit (OpCodes.Bgt, target);
4641 ec.Emit (OpCodes.Ble_Un, target);
4643 ec.Emit (OpCodes.Ble, target);
4646 case Operator.LessThanOrEqual:
4648 if (is_unsigned && !is_float)
4649 ec.Emit (OpCodes.Ble_Un, target);
4651 ec.Emit (OpCodes.Ble, target);
4654 ec.Emit (OpCodes.Bgt_Un, target);
4656 ec.Emit (OpCodes.Bgt, target);
4660 case Operator.GreaterThanOrEqual:
4662 if (is_unsigned && !is_float)
4663 ec.Emit (OpCodes.Bge_Un, target);
4665 ec.Emit (OpCodes.Bge, target);
4668 ec.Emit (OpCodes.Blt_Un, target);
4670 ec.Emit (OpCodes.Blt, target);
4673 throw new InternalErrorException (oper.ToString ());
4677 public override void Emit (EmitContext ec)
4679 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4680 left = left.EmitToField (ec);
4682 if ((oper & Operator.LogicalMask) == 0) {
4683 right = right.EmitToField (ec);
4688 // Handle short-circuit operators differently
4691 if ((oper & Operator.LogicalMask) != 0) {
4692 Label load_result = ec.DefineLabel ();
4693 Label end = ec.DefineLabel ();
4695 bool is_or = oper == Operator.LogicalOr;
4696 left.EmitBranchable (ec, load_result, is_or);
4698 ec.Emit (OpCodes.Br_S, end);
4700 ec.MarkLabel (load_result);
4701 ec.EmitInt (is_or ? 1 : 0);
4707 // Optimize zero-based operations which cannot be optimized at expression level
4709 if (oper == Operator.Subtraction) {
4710 var lc = left as IntegralConstant;
4711 if (lc != null && lc.IsDefaultValue) {
4713 ec.Emit (OpCodes.Neg);
4718 EmitOperator (ec, left, right);
4721 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4726 EmitOperatorOpcode (ec, oper, left.Type, right);
4729 // Emit result enumerable conversion this way because it's quite complicated get it
4730 // to resolved tree because expression tree cannot see it.
4732 if (enum_conversion != 0)
4733 ConvCast.Emit (ec, enum_conversion);
4736 public override void EmitSideEffect (EmitContext ec)
4738 if ((oper & Operator.LogicalMask) != 0 ||
4739 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4740 base.EmitSideEffect (ec);
4742 left.EmitSideEffect (ec);
4743 right.EmitSideEffect (ec);
4747 public override Expression EmitToField (EmitContext ec)
4749 if ((oper & Operator.LogicalMask) == 0) {
4750 var await_expr = left as Await;
4751 if (await_expr != null && right.IsSideEffectFree) {
4752 await_expr.Statement.EmitPrologue (ec);
4753 left = await_expr.Statement.GetResultExpression (ec);
4757 await_expr = right as Await;
4758 if (await_expr != null && left.IsSideEffectFree) {
4759 await_expr.Statement.EmitPrologue (ec);
4760 right = await_expr.Statement.GetResultExpression (ec);
4765 return base.EmitToField (ec);
4768 protected override void CloneTo (CloneContext clonectx, Expression t)
4770 Binary target = (Binary) t;
4772 target.left = left.Clone (clonectx);
4773 target.right = right.Clone (clonectx);
4776 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4778 Arguments binder_args = new Arguments (4);
4780 MemberAccess sle = new MemberAccess (new MemberAccess (
4781 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4783 CSharpBinderFlags flags = 0;
4784 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4785 flags = CSharpBinderFlags.CheckedContext;
4787 if ((oper & Operator.LogicalMask) != 0)
4788 flags |= CSharpBinderFlags.BinaryOperationLogical;
4790 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4791 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4792 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4793 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4795 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4798 public override Expression CreateExpressionTree (ResolveContext ec)
4800 return CreateExpressionTree (ec, null);
4803 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4806 bool lift_arg = false;
4809 case Operator.Addition:
4810 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4811 method_name = "AddChecked";
4813 method_name = "Add";
4815 case Operator.BitwiseAnd:
4816 method_name = "And";
4818 case Operator.BitwiseOr:
4821 case Operator.Division:
4822 method_name = "Divide";
4824 case Operator.Equality:
4825 method_name = "Equal";
4828 case Operator.ExclusiveOr:
4829 method_name = "ExclusiveOr";
4831 case Operator.GreaterThan:
4832 method_name = "GreaterThan";
4835 case Operator.GreaterThanOrEqual:
4836 method_name = "GreaterThanOrEqual";
4839 case Operator.Inequality:
4840 method_name = "NotEqual";
4843 case Operator.LeftShift:
4844 method_name = "LeftShift";
4846 case Operator.LessThan:
4847 method_name = "LessThan";
4850 case Operator.LessThanOrEqual:
4851 method_name = "LessThanOrEqual";
4854 case Operator.LogicalAnd:
4855 method_name = "AndAlso";
4857 case Operator.LogicalOr:
4858 method_name = "OrElse";
4860 case Operator.Modulus:
4861 method_name = "Modulo";
4863 case Operator.Multiply:
4864 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4865 method_name = "MultiplyChecked";
4867 method_name = "Multiply";
4869 case Operator.RightShift:
4870 method_name = "RightShift";
4872 case Operator.Subtraction:
4873 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4874 method_name = "SubtractChecked";
4876 method_name = "Subtract";
4880 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4883 Arguments args = new Arguments (2);
4884 args.Add (new Argument (left.CreateExpressionTree (ec)));
4885 args.Add (new Argument (right.CreateExpressionTree (ec)));
4886 if (method != null) {
4888 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4890 args.Add (new Argument (method));
4893 return CreateExpressionFactoryCall (ec, method_name, args);
4896 public override object Accept (StructuralVisitor visitor)
4898 return visitor.Visit (this);
4904 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4905 // b, c, d... may be strings or objects.
4907 public class StringConcat : Expression
4909 Arguments arguments;
4911 StringConcat (Location loc)
4914 arguments = new Arguments (2);
4917 public override bool ContainsEmitWithAwait ()
4919 return arguments.ContainsEmitWithAwait ();
4922 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4924 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4925 throw new ArgumentException ();
4927 var s = new StringConcat (loc);
4928 s.type = rc.BuiltinTypes.String;
4929 s.eclass = ExprClass.Value;
4931 s.Append (rc, left);
4932 s.Append (rc, right);
4936 public override Expression CreateExpressionTree (ResolveContext ec)
4938 Argument arg = arguments [0];
4939 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4943 // Creates nested calls tree from an array of arguments used for IL emit
4945 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4947 Arguments concat_args = new Arguments (2);
4948 Arguments add_args = new Arguments (3);
4950 concat_args.Add (left);
4951 add_args.Add (new Argument (left_etree));
4953 concat_args.Add (arguments [pos]);
4954 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4956 var methods = GetConcatMethodCandidates ();
4957 if (methods == null)
4960 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4961 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4965 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4967 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4968 if (++pos == arguments.Count)
4971 left = new Argument (new EmptyExpression (method.ReturnType));
4972 return CreateExpressionAddCall (ec, left, expr, pos);
4975 protected override Expression DoResolve (ResolveContext ec)
4980 void Append (ResolveContext rc, Expression operand)
4985 StringConstant sc = operand as StringConstant;
4987 if (arguments.Count != 0) {
4988 Argument last_argument = arguments [arguments.Count - 1];
4989 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4990 if (last_expr_constant != null) {
4991 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4997 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4999 StringConcat concat_oper = operand as StringConcat;
5000 if (concat_oper != null) {
5001 arguments.AddRange (concat_oper.arguments);
5006 arguments.Add (new Argument (operand));
5009 IList<MemberSpec> GetConcatMethodCandidates ()
5011 return MemberCache.FindMembers (type, "Concat", true);
5014 public override void Emit (EmitContext ec)
5016 // Optimize by removing any extra null arguments, they are no-op
5017 for (int i = 0; i < arguments.Count; ++i) {
5018 if (arguments[i].Expr is NullConstant)
5019 arguments.RemoveAt (i--);
5022 var members = GetConcatMethodCandidates ();
5023 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5024 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5025 if (method != null) {
5026 var call = new CallEmitter ();
5027 call.EmitPredefined (ec, method, arguments);
5031 public override void FlowAnalysis (FlowAnalysisContext fc)
5033 arguments.FlowAnalysis (fc);
5036 public override SLE.Expression MakeExpression (BuilderContext ctx)
5038 if (arguments.Count != 2)
5039 throw new NotImplementedException ("arguments.Count != 2");
5041 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5042 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5047 // User-defined conditional logical operator
5049 public class ConditionalLogicalOperator : UserOperatorCall
5051 readonly bool is_and;
5052 Expression oper_expr;
5054 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5055 : base (oper, arguments, expr_tree, loc)
5057 this.is_and = is_and;
5058 eclass = ExprClass.Unresolved;
5061 protected override Expression DoResolve (ResolveContext ec)
5063 AParametersCollection pd = oper.Parameters;
5064 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5065 ec.Report.Error (217, loc,
5066 "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",
5067 oper.GetSignatureForError ());
5071 Expression left_dup = new EmptyExpression (type);
5072 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5073 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5074 if (op_true == null || op_false == null) {
5075 ec.Report.Error (218, loc,
5076 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5077 type.GetSignatureForError (), oper.GetSignatureForError ());
5081 oper_expr = is_and ? op_false : op_true;
5082 eclass = ExprClass.Value;
5086 public override void Emit (EmitContext ec)
5088 Label end_target = ec.DefineLabel ();
5091 // Emit and duplicate left argument
5093 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5094 if (right_contains_await) {
5095 arguments[0] = arguments[0].EmitToField (ec, false);
5096 arguments[0].Expr.Emit (ec);
5098 arguments[0].Expr.Emit (ec);
5099 ec.Emit (OpCodes.Dup);
5100 arguments.RemoveAt (0);
5103 oper_expr.EmitBranchable (ec, end_target, true);
5107 if (right_contains_await) {
5109 // Special handling when right expression contains await and left argument
5110 // could not be left on stack before logical branch
5112 Label skip_left_load = ec.DefineLabel ();
5113 ec.Emit (OpCodes.Br_S, skip_left_load);
5114 ec.MarkLabel (end_target);
5115 arguments[0].Expr.Emit (ec);
5116 ec.MarkLabel (skip_left_load);
5118 ec.MarkLabel (end_target);
5123 public class PointerArithmetic : Expression {
5124 Expression left, right;
5125 readonly Binary.Operator op;
5128 // We assume that `l' is always a pointer
5130 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5139 public override bool ContainsEmitWithAwait ()
5141 throw new NotImplementedException ();
5144 public override Expression CreateExpressionTree (ResolveContext ec)
5146 Error_PointerInsideExpressionTree (ec);
5150 protected override Expression DoResolve (ResolveContext ec)
5152 eclass = ExprClass.Variable;
5154 var pc = left.Type as PointerContainer;
5155 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5156 Error_VoidPointerOperation (ec);
5163 public override void Emit (EmitContext ec)
5165 TypeSpec op_type = left.Type;
5167 // It must be either array or fixed buffer
5169 if (TypeManager.HasElementType (op_type)) {
5170 element = TypeManager.GetElementType (op_type);
5172 FieldExpr fe = left as FieldExpr;
5174 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5179 int size = BuiltinTypeSpec.GetSize(element);
5180 TypeSpec rtype = right.Type;
5182 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5184 // handle (pointer - pointer)
5188 ec.Emit (OpCodes.Sub);
5192 ec.Emit (OpCodes.Sizeof, element);
5195 ec.Emit (OpCodes.Div);
5197 ec.Emit (OpCodes.Conv_I8);
5200 // handle + and - on (pointer op int)
5202 Constant left_const = left as Constant;
5203 if (left_const != null) {
5205 // Optimize ((T*)null) pointer operations
5207 if (left_const.IsDefaultValue) {
5208 left = EmptyExpression.Null;
5216 var right_const = right as Constant;
5217 if (right_const != null) {
5219 // Optimize 0-based arithmetic
5221 if (right_const.IsDefaultValue)
5225 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5227 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5229 // TODO: Should be the checks resolve context sensitive?
5230 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5231 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5237 switch (rtype.BuiltinType) {
5238 case BuiltinTypeSpec.Type.SByte:
5239 case BuiltinTypeSpec.Type.Byte:
5240 case BuiltinTypeSpec.Type.Short:
5241 case BuiltinTypeSpec.Type.UShort:
5242 ec.Emit (OpCodes.Conv_I);
5244 case BuiltinTypeSpec.Type.UInt:
5245 ec.Emit (OpCodes.Conv_U);
5249 if (right_const == null && size != 1){
5251 ec.Emit (OpCodes.Sizeof, element);
5254 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5255 ec.Emit (OpCodes.Conv_I8);
5257 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5260 if (left_const == null) {
5261 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5262 ec.Emit (OpCodes.Conv_I);
5263 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5264 ec.Emit (OpCodes.Conv_U);
5266 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5273 // A boolean-expression is an expression that yields a result
5276 public class BooleanExpression : ShimExpression
5278 public BooleanExpression (Expression expr)
5281 this.loc = expr.Location;
5284 public override Expression CreateExpressionTree (ResolveContext ec)
5286 // TODO: We should emit IsTrue (v4) instead of direct user operator
5287 // call but that would break csc compatibility
5288 return base.CreateExpressionTree (ec);
5291 protected override Expression DoResolve (ResolveContext ec)
5293 // A boolean-expression is required to be of a type
5294 // that can be implicitly converted to bool or of
5295 // a type that implements operator true
5297 expr = expr.Resolve (ec);
5301 Assign ass = expr as Assign;
5302 if (ass != null && ass.Source is Constant) {
5303 ec.Report.Warning (665, 3, loc,
5304 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5307 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5310 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5311 Arguments args = new Arguments (1);
5312 args.Add (new Argument (expr));
5313 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5316 type = ec.BuiltinTypes.Bool;
5317 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5318 if (converted != null)
5322 // If no implicit conversion to bool exists, try using `operator true'
5324 converted = GetOperatorTrue (ec, expr, loc);
5325 if (converted == null) {
5326 expr.Error_ValueCannotBeConverted (ec, type, false);
5333 public override object Accept (StructuralVisitor visitor)
5335 return visitor.Visit (this);
5339 public class BooleanExpressionFalse : Unary
5341 public BooleanExpressionFalse (Expression expr)
5342 : base (Operator.LogicalNot, expr, expr.Location)
5346 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5348 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5353 /// Implements the ternary conditional operator (?:)
5355 public class Conditional : Expression {
5356 Expression expr, true_expr, false_expr;
5358 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5361 this.true_expr = true_expr;
5362 this.false_expr = false_expr;
5368 public Expression Expr {
5374 public Expression TrueExpr {
5380 public Expression FalseExpr {
5388 public override bool ContainsEmitWithAwait ()
5390 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5393 public override Expression CreateExpressionTree (ResolveContext ec)
5395 Arguments args = new Arguments (3);
5396 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5397 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5398 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5399 return CreateExpressionFactoryCall (ec, "Condition", args);
5402 protected override Expression DoResolve (ResolveContext ec)
5404 expr = expr.Resolve (ec);
5405 true_expr = true_expr.Resolve (ec);
5406 false_expr = false_expr.Resolve (ec);
5408 if (true_expr == null || false_expr == null || expr == null)
5411 eclass = ExprClass.Value;
5412 TypeSpec true_type = true_expr.Type;
5413 TypeSpec false_type = false_expr.Type;
5417 // First, if an implicit conversion exists from true_expr
5418 // to false_expr, then the result type is of type false_expr.Type
5420 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5421 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5422 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5424 // Check if both can convert implicitly to each other's type
5428 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5429 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5431 // LAMESPEC: There seems to be hardcoded promotition to int type when
5432 // both sides are numeric constants and one side is int constant and
5433 // other side is numeric constant convertible to int.
5435 // var res = condition ? (short)1 : 1;
5437 // Type of res is int even if according to the spec the conversion is
5438 // ambiguous because 1 literal can be converted to short.
5440 if (conv_false_expr != null) {
5441 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5443 conv_false_expr = null;
5444 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5445 conv_false_expr = null;
5449 if (conv_false_expr != null) {
5450 ec.Report.Error (172, true_expr.Location,
5451 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5452 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5457 if (true_expr.Type != type)
5458 true_expr = EmptyCast.Create (true_expr, type);
5459 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5462 ec.Report.Error (173, true_expr.Location,
5463 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5464 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5469 Constant c = expr as Constant;
5471 bool is_false = c.IsDefaultValue;
5474 // Don't issue the warning for constant expressions
5476 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5477 // CSC: Missing warning
5478 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
5481 return ReducedExpression.Create (
5482 is_false ? false_expr : true_expr, this,
5483 false_expr is Constant && true_expr is Constant).Resolve (ec);
5489 public override void Emit (EmitContext ec)
5491 Label false_target = ec.DefineLabel ();
5492 Label end_target = ec.DefineLabel ();
5494 expr.EmitBranchable (ec, false_target, false);
5495 true_expr.Emit (ec);
5498 // Verifier doesn't support interface merging. When there are two types on
5499 // the stack without common type hint and the common type is an interface.
5500 // Use temporary local to give verifier hint on what type to unify the stack
5502 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5503 var temp = ec.GetTemporaryLocal (type);
5504 ec.Emit (OpCodes.Stloc, temp);
5505 ec.Emit (OpCodes.Ldloc, temp);
5506 ec.FreeTemporaryLocal (temp, type);
5509 ec.Emit (OpCodes.Br, end_target);
5510 ec.MarkLabel (false_target);
5511 false_expr.Emit (ec);
5512 ec.MarkLabel (end_target);
5515 public override void FlowAnalysis (FlowAnalysisContext fc)
5517 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5519 expr.FlowAnalysis (fc);
5520 var da_true = fc.DefiniteAssignmentOnTrue;
5521 var da_false = fc.DefiniteAssignmentOnFalse;
5523 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_true);
5524 true_expr.FlowAnalysis (fc);
5525 var true_fc = fc.DefiniteAssignment;
5527 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_false);
5528 false_expr.FlowAnalysis (fc);
5530 fc.DefiniteAssignment &= true_fc;
5531 if (fc.DefiniteAssignmentOnTrue != null)
5532 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
5533 if (fc.DefiniteAssignmentOnFalse != null)
5534 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5537 protected override void CloneTo (CloneContext clonectx, Expression t)
5539 Conditional target = (Conditional) t;
5541 target.expr = expr.Clone (clonectx);
5542 target.true_expr = true_expr.Clone (clonectx);
5543 target.false_expr = false_expr.Clone (clonectx);
5547 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5549 LocalTemporary temp;
5552 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5553 public abstract void SetHasAddressTaken ();
5555 public abstract bool IsLockedByStatement { get; set; }
5557 public abstract bool IsFixed { get; }
5558 public abstract bool IsRef { get; }
5559 public abstract string Name { get; }
5562 // Variable IL data, it has to be protected to encapsulate hoisted variables
5564 protected abstract ILocalVariable Variable { get; }
5567 // Variable flow-analysis data
5569 public abstract VariableInfo VariableInfo { get; }
5572 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5574 HoistedVariable hv = GetHoistedVariable (ec);
5576 hv.AddressOf (ec, mode);
5580 Variable.EmitAddressOf (ec);
5583 public override bool ContainsEmitWithAwait ()
5588 public override Expression CreateExpressionTree (ResolveContext ec)
5590 HoistedVariable hv = GetHoistedVariable (ec);
5592 return hv.CreateExpressionTree ();
5594 Arguments arg = new Arguments (1);
5595 arg.Add (new Argument (this));
5596 return CreateExpressionFactoryCall (ec, "Constant", arg);
5599 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5601 if (IsLockedByStatement) {
5602 rc.Report.Warning (728, 2, loc,
5603 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5610 public override void Emit (EmitContext ec)
5615 public override void EmitSideEffect (EmitContext ec)
5621 // This method is used by parameters that are references, that are
5622 // being passed as references: we only want to pass the pointer (that
5623 // is already stored in the parameter, not the address of the pointer,
5624 // and not the value of the variable).
5626 public void EmitLoad (EmitContext ec)
5631 public void Emit (EmitContext ec, bool leave_copy)
5633 HoistedVariable hv = GetHoistedVariable (ec);
5635 hv.Emit (ec, leave_copy);
5643 // If we are a reference, we loaded on the stack a pointer
5644 // Now lets load the real value
5646 ec.EmitLoadFromPtr (type);
5650 ec.Emit (OpCodes.Dup);
5653 temp = new LocalTemporary (Type);
5659 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5660 bool prepare_for_load)
5662 HoistedVariable hv = GetHoistedVariable (ec);
5664 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5668 New n_source = source as New;
5669 if (n_source != null) {
5670 if (!n_source.Emit (ec, this)) {
5674 ec.EmitLoadFromPtr (type);
5686 ec.Emit (OpCodes.Dup);
5688 temp = new LocalTemporary (Type);
5694 ec.EmitStoreFromPtr (type);
5696 Variable.EmitAssign (ec);
5704 public override Expression EmitToField (EmitContext ec)
5706 HoistedVariable hv = GetHoistedVariable (ec);
5708 return hv.EmitToField (ec);
5711 return base.EmitToField (ec);
5714 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5716 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5719 public HoistedVariable GetHoistedVariable (EmitContext ec)
5721 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5724 public override string GetSignatureForError ()
5729 public bool IsHoisted {
5730 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5735 // Resolved reference to a local variable
5737 public class LocalVariableReference : VariableReference
5739 public LocalVariable local_info;
5741 public LocalVariableReference (LocalVariable li, Location l)
5743 this.local_info = li;
5747 public override VariableInfo VariableInfo {
5748 get { return local_info.VariableInfo; }
5751 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5753 return local_info.HoistedVariant;
5759 // A local variable is always fixed
5761 public override bool IsFixed {
5767 public override bool IsLockedByStatement {
5769 return local_info.IsLocked;
5772 local_info.IsLocked = value;
5776 public override bool IsRef {
5777 get { return false; }
5780 public override string Name {
5781 get { return local_info.Name; }
5786 public override void FlowAnalysis (FlowAnalysisContext fc)
5788 VariableInfo variable_info = VariableInfo;
5789 if (variable_info == null)
5792 if (fc.IsDefinitelyAssigned (variable_info))
5795 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5796 variable_info.SetAssigned (fc.DefiniteAssignment, true);
5799 public override void SetHasAddressTaken ()
5801 local_info.SetHasAddressTaken ();
5804 void DoResolveBase (ResolveContext ec)
5807 // If we are referencing a variable from the external block
5808 // flag it for capturing
5810 if (ec.MustCaptureVariable (local_info)) {
5811 if (local_info.AddressTaken) {
5812 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5813 } else if (local_info.IsFixed) {
5814 ec.Report.Error (1764, loc,
5815 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5816 GetSignatureForError ());
5819 if (ec.IsVariableCapturingRequired) {
5820 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5821 storey.CaptureLocalVariable (ec, local_info);
5825 eclass = ExprClass.Variable;
5826 type = local_info.Type;
5829 protected override Expression DoResolve (ResolveContext ec)
5831 local_info.SetIsUsed ();
5837 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5840 // Don't be too pedantic when variable is used as out param or for some broken code
5841 // which uses property/indexer access to run some initialization
5843 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5844 local_info.SetIsUsed ();
5846 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5847 if (rhs == EmptyExpression.LValueMemberAccess) {
5848 // CS1654 already reported
5852 if (rhs == EmptyExpression.OutAccess) {
5853 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5854 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5855 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5856 } else if (rhs == EmptyExpression.UnaryAddress) {
5857 code = 459; msg = "Cannot take the address of {1} `{0}'";
5859 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5861 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5865 if (eclass == ExprClass.Unresolved)
5868 return base.DoResolveLValue (ec, rhs);
5871 public override int GetHashCode ()
5873 return local_info.GetHashCode ();
5876 public override bool Equals (object obj)
5878 LocalVariableReference lvr = obj as LocalVariableReference;
5882 return local_info == lvr.local_info;
5885 protected override ILocalVariable Variable {
5886 get { return local_info; }
5889 public override string ToString ()
5891 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5894 protected override void CloneTo (CloneContext clonectx, Expression t)
5901 /// This represents a reference to a parameter in the intermediate
5904 public class ParameterReference : VariableReference
5906 protected ParametersBlock.ParameterInfo pi;
5908 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5916 public override bool IsLockedByStatement {
5921 pi.IsLocked = value;
5925 public override bool IsRef {
5926 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5929 bool HasOutModifier {
5930 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5933 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5935 return pi.Parameter.HoistedVariant;
5939 // A ref or out parameter is classified as a moveable variable, even
5940 // if the argument given for the parameter is a fixed variable
5942 public override bool IsFixed {
5943 get { return !IsRef; }
5946 public override string Name {
5947 get { return Parameter.Name; }
5950 public Parameter Parameter {
5951 get { return pi.Parameter; }
5954 public override VariableInfo VariableInfo {
5955 get { return pi.VariableInfo; }
5958 protected override ILocalVariable Variable {
5959 get { return Parameter; }
5964 public override void AddressOf (EmitContext ec, AddressOp mode)
5967 // ParameterReferences might already be a reference
5974 base.AddressOf (ec, mode);
5977 public override void SetHasAddressTaken ()
5979 Parameter.HasAddressTaken = true;
5982 bool DoResolveBase (ResolveContext ec)
5984 if (eclass != ExprClass.Unresolved)
5987 type = pi.ParameterType;
5988 eclass = ExprClass.Variable;
5991 // If we are referencing a parameter from the external block
5992 // flag it for capturing
5994 if (ec.MustCaptureVariable (pi)) {
5995 if (Parameter.HasAddressTaken)
5996 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5999 ec.Report.Error (1628, loc,
6000 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6001 Name, ec.CurrentAnonymousMethod.ContainerType);
6004 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6005 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6006 storey.CaptureParameter (ec, pi, this);
6013 public override int GetHashCode ()
6015 return Name.GetHashCode ();
6018 public override bool Equals (object obj)
6020 ParameterReference pr = obj as ParameterReference;
6024 return Name == pr.Name;
6027 protected override void CloneTo (CloneContext clonectx, Expression target)
6033 public override Expression CreateExpressionTree (ResolveContext ec)
6035 HoistedVariable hv = GetHoistedVariable (ec);
6037 return hv.CreateExpressionTree ();
6039 return Parameter.ExpressionTreeVariableReference ();
6042 protected override Expression DoResolve (ResolveContext ec)
6044 if (!DoResolveBase (ec))
6050 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6052 if (!DoResolveBase (ec))
6055 if (Parameter.HoistedVariant != null)
6056 Parameter.HoistedVariant.IsAssigned = true;
6058 return base.DoResolveLValue (ec, right_side);
6061 public override void FlowAnalysis (FlowAnalysisContext fc)
6063 VariableInfo variable_info = VariableInfo;
6064 if (variable_info == null)
6067 if (fc.IsDefinitelyAssigned (variable_info))
6070 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6071 fc.SetVariableAssigned (variable_info);
6076 /// Invocation of methods or delegates.
6078 public class Invocation : ExpressionStatement
6080 protected Arguments arguments;
6081 protected Expression expr;
6082 protected MethodGroupExpr mg;
6084 public Invocation (Expression expr, Arguments arguments)
6087 this.arguments = arguments;
6089 loc = expr.Location;
6094 public Arguments Arguments {
6100 public Expression Exp {
6106 public MethodGroupExpr MethodGroup {
6112 public override Location StartLocation {
6114 return expr.StartLocation;
6120 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6122 if (MethodGroup == null)
6125 var candidate = MethodGroup.BestCandidate;
6126 if (candidate == null || !(candidate.IsStatic || Exp is This))
6129 var args_count = arguments == null ? 0 : arguments.Count;
6130 if (args_count != body.Parameters.Count)
6133 var lambda_parameters = body.Block.Parameters.FixedParameters;
6134 for (int i = 0; i < args_count; ++i) {
6135 var pr = arguments[i].Expr as ParameterReference;
6139 if (lambda_parameters[i] != pr.Parameter)
6142 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6146 var emg = MethodGroup as ExtensionMethodGroupExpr;
6148 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6149 if (candidate.IsGeneric) {
6150 var targs = new TypeExpression [candidate.Arity];
6151 for (int i = 0; i < targs.Length; ++i) {
6152 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6155 mg.SetTypeArguments (null, new TypeArguments (targs));
6164 protected override void CloneTo (CloneContext clonectx, Expression t)
6166 Invocation target = (Invocation) t;
6168 if (arguments != null)
6169 target.arguments = arguments.Clone (clonectx);
6171 target.expr = expr.Clone (clonectx);
6174 public override bool ContainsEmitWithAwait ()
6176 if (arguments != null && arguments.ContainsEmitWithAwait ())
6179 return mg.ContainsEmitWithAwait ();
6182 public override Expression CreateExpressionTree (ResolveContext ec)
6184 Expression instance = mg.IsInstance ?
6185 mg.InstanceExpression.CreateExpressionTree (ec) :
6186 new NullLiteral (loc);
6188 var args = Arguments.CreateForExpressionTree (ec, arguments,
6190 mg.CreateExpressionTree (ec));
6192 return CreateExpressionFactoryCall (ec, "Call", args);
6195 protected override Expression DoResolve (ResolveContext ec)
6197 Expression member_expr;
6198 var atn = expr as ATypeNameExpression;
6200 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6201 if (member_expr != null)
6202 member_expr = member_expr.Resolve (ec);
6204 member_expr = expr.Resolve (ec);
6207 if (member_expr == null)
6211 // Next, evaluate all the expressions in the argument list
6213 bool dynamic_arg = false;
6214 if (arguments != null)
6215 arguments.Resolve (ec, out dynamic_arg);
6217 TypeSpec expr_type = member_expr.Type;
6218 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6219 return DoResolveDynamic (ec, member_expr);
6221 mg = member_expr as MethodGroupExpr;
6222 Expression invoke = null;
6225 if (expr_type != null && expr_type.IsDelegate) {
6226 invoke = new DelegateInvocation (member_expr, arguments, loc);
6227 invoke = invoke.Resolve (ec);
6228 if (invoke == null || !dynamic_arg)
6231 if (member_expr is RuntimeValueExpression) {
6232 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6233 member_expr.Type.GetSignatureForError ());
6237 MemberExpr me = member_expr as MemberExpr;
6239 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6243 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6244 member_expr.GetSignatureForError ());
6249 if (invoke == null) {
6250 mg = DoResolveOverload (ec);
6256 return DoResolveDynamic (ec, member_expr);
6258 var method = mg.BestCandidate;
6259 type = mg.BestCandidateReturnType;
6261 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6263 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6265 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6269 IsSpecialMethodInvocation (ec, method, loc);
6271 eclass = ExprClass.Value;
6275 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6278 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6280 args = dmb.Arguments;
6281 if (arguments != null)
6282 args.AddRange (arguments);
6283 } else if (mg == null) {
6284 if (arguments == null)
6285 args = new Arguments (1);
6289 args.Insert (0, new Argument (memberExpr));
6293 ec.Report.Error (1971, loc,
6294 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6299 if (arguments == null)
6300 args = new Arguments (1);
6304 MemberAccess ma = expr as MemberAccess;
6306 var left_type = ma.LeftExpression as TypeExpr;
6307 if (left_type != null) {
6308 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6311 // Any value type has to be pass as by-ref to get back the same
6312 // instance on which the member was called
6314 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6315 Argument.AType.Ref : Argument.AType.None;
6316 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6318 } else { // is SimpleName
6320 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6322 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6327 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6330 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6332 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6335 public override void FlowAnalysis (FlowAnalysisContext fc)
6337 if (mg.IsConditionallyExcluded)
6340 mg.FlowAnalysis (fc);
6342 if (arguments != null)
6343 arguments.FlowAnalysis (fc);
6346 public override string GetSignatureForError ()
6348 return mg.GetSignatureForError ();
6352 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6353 // or the type dynamic, then the member is invocable
6355 public static bool IsMemberInvocable (MemberSpec member)
6357 switch (member.Kind) {
6358 case MemberKind.Event:
6360 case MemberKind.Field:
6361 case MemberKind.Property:
6362 var m = member as IInterfaceMemberSpec;
6363 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6369 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6371 if (!method.IsReservedMethod)
6374 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6377 ec.Report.SymbolRelatedToPreviousError (method);
6378 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6379 method.GetSignatureForError ());
6384 public override void Emit (EmitContext ec)
6386 if (mg.IsConditionallyExcluded)
6389 mg.EmitCall (ec, arguments);
6392 public override void EmitStatement (EmitContext ec)
6397 // Pop the return value if there is one
6399 if (type.Kind != MemberKind.Void)
6400 ec.Emit (OpCodes.Pop);
6403 public override SLE.Expression MakeExpression (BuilderContext ctx)
6405 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6408 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6411 throw new NotSupportedException ();
6413 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6414 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6418 public override object Accept (StructuralVisitor visitor)
6420 return visitor.Visit (this);
6425 // Implements simple new expression
6427 public class New : ExpressionStatement, IMemoryLocation
6429 protected Arguments arguments;
6432 // During bootstrap, it contains the RequestedType,
6433 // but if `type' is not null, it *might* contain a NewDelegate
6434 // (because of field multi-initialization)
6436 protected Expression RequestedType;
6438 protected MethodSpec method;
6440 public New (Expression requested_type, Arguments arguments, Location l)
6442 RequestedType = requested_type;
6443 this.arguments = arguments;
6448 public Arguments Arguments {
6455 // Returns true for resolved `new S()'
6457 public bool IsDefaultStruct {
6459 return arguments == null && type.IsStruct && GetType () == typeof (New);
6463 public Expression TypeExpression {
6465 return RequestedType;
6472 /// Converts complex core type syntax like 'new int ()' to simple constant
6474 public static Constant Constantify (TypeSpec t, Location loc)
6476 switch (t.BuiltinType) {
6477 case BuiltinTypeSpec.Type.Int:
6478 return new IntConstant (t, 0, loc);
6479 case BuiltinTypeSpec.Type.UInt:
6480 return new UIntConstant (t, 0, loc);
6481 case BuiltinTypeSpec.Type.Long:
6482 return new LongConstant (t, 0, loc);
6483 case BuiltinTypeSpec.Type.ULong:
6484 return new ULongConstant (t, 0, loc);
6485 case BuiltinTypeSpec.Type.Float:
6486 return new FloatConstant (t, 0, loc);
6487 case BuiltinTypeSpec.Type.Double:
6488 return new DoubleConstant (t, 0, loc);
6489 case BuiltinTypeSpec.Type.Short:
6490 return new ShortConstant (t, 0, loc);
6491 case BuiltinTypeSpec.Type.UShort:
6492 return new UShortConstant (t, 0, loc);
6493 case BuiltinTypeSpec.Type.SByte:
6494 return new SByteConstant (t, 0, loc);
6495 case BuiltinTypeSpec.Type.Byte:
6496 return new ByteConstant (t, 0, loc);
6497 case BuiltinTypeSpec.Type.Char:
6498 return new CharConstant (t, '\0', loc);
6499 case BuiltinTypeSpec.Type.Bool:
6500 return new BoolConstant (t, false, loc);
6501 case BuiltinTypeSpec.Type.Decimal:
6502 return new DecimalConstant (t, 0, loc);
6506 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6508 if (t.IsNullableType)
6509 return Nullable.LiftedNull.Create (t, loc);
6514 public override bool ContainsEmitWithAwait ()
6516 return arguments != null && arguments.ContainsEmitWithAwait ();
6520 // Checks whether the type is an interface that has the
6521 // [ComImport, CoClass] attributes and must be treated
6524 public Expression CheckComImport (ResolveContext ec)
6526 if (!type.IsInterface)
6530 // Turn the call into:
6531 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6533 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6534 if (real_class == null)
6537 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6538 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6539 return cast.Resolve (ec);
6542 public override Expression CreateExpressionTree (ResolveContext ec)
6545 if (method == null) {
6546 args = new Arguments (1);
6547 args.Add (new Argument (new TypeOf (type, loc)));
6549 args = Arguments.CreateForExpressionTree (ec,
6550 arguments, new TypeOfMethod (method, loc));
6553 return CreateExpressionFactoryCall (ec, "New", args);
6556 protected override Expression DoResolve (ResolveContext ec)
6558 type = RequestedType.ResolveAsType (ec);
6562 eclass = ExprClass.Value;
6564 if (type.IsPointer) {
6565 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6566 type.GetSignatureForError ());
6570 if (arguments == null) {
6571 Constant c = Constantify (type, RequestedType.Location);
6573 return ReducedExpression.Create (c, this);
6576 if (type.IsDelegate) {
6577 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6580 var tparam = type as TypeParameterSpec;
6581 if (tparam != null) {
6583 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6584 // where type parameter constraint is inflated to struct
6586 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6587 ec.Report.Error (304, loc,
6588 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6589 type.GetSignatureForError ());
6592 if ((arguments != null) && (arguments.Count != 0)) {
6593 ec.Report.Error (417, loc,
6594 "`{0}': cannot provide arguments when creating an instance of a variable type",
6595 type.GetSignatureForError ());
6601 if (type.IsStatic) {
6602 ec.Report.SymbolRelatedToPreviousError (type);
6603 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6607 if (type.IsInterface || type.IsAbstract){
6608 if (!TypeManager.IsGenericType (type)) {
6609 RequestedType = CheckComImport (ec);
6610 if (RequestedType != null)
6611 return RequestedType;
6614 ec.Report.SymbolRelatedToPreviousError (type);
6615 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6620 // Any struct always defines parameterless constructor
6622 if (type.IsStruct && arguments == null)
6626 if (arguments != null) {
6627 arguments.Resolve (ec, out dynamic);
6632 method = ConstructorLookup (ec, type, ref arguments, loc);
6635 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6636 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6642 bool DoEmitTypeParameter (EmitContext ec)
6644 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6648 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6649 var tparam = (TypeParameterSpec) type;
6651 if (tparam.IsReferenceType) {
6652 ec.Emit (OpCodes.Call, ctor_factory);
6656 // Allow DoEmit() to be called multiple times.
6657 // We need to create a new LocalTemporary each time since
6658 // you can't share LocalBuilders among ILGeneators.
6659 LocalTemporary temp = new LocalTemporary (type);
6661 Label label_activator = ec.DefineLabel ();
6662 Label label_end = ec.DefineLabel ();
6664 temp.AddressOf (ec, AddressOp.Store);
6665 ec.Emit (OpCodes.Initobj, type);
6668 ec.Emit (OpCodes.Box, type);
6669 ec.Emit (OpCodes.Brfalse, label_activator);
6671 temp.AddressOf (ec, AddressOp.Store);
6672 ec.Emit (OpCodes.Initobj, type);
6675 ec.Emit (OpCodes.Br_S, label_end);
6677 ec.MarkLabel (label_activator);
6679 ec.Emit (OpCodes.Call, ctor_factory);
6680 ec.MarkLabel (label_end);
6685 // This Emit can be invoked in two contexts:
6686 // * As a mechanism that will leave a value on the stack (new object)
6687 // * As one that wont (init struct)
6689 // If we are dealing with a ValueType, we have a few
6690 // situations to deal with:
6692 // * The target is a ValueType, and we have been provided
6693 // the instance (this is easy, we are being assigned).
6695 // * The target of New is being passed as an argument,
6696 // to a boxing operation or a function that takes a
6699 // In this case, we need to create a temporary variable
6700 // that is the argument of New.
6702 // Returns whether a value is left on the stack
6704 // *** Implementation note ***
6706 // To benefit from this optimization, each assignable expression
6707 // has to manually cast to New and call this Emit.
6709 // TODO: It's worth to implement it for arrays and fields
6711 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6713 bool is_value_type = TypeSpec.IsValueType (type);
6714 VariableReference vr = target as VariableReference;
6716 if (target != null && is_value_type && (vr != null || method == null)) {
6717 target.AddressOf (ec, AddressOp.Store);
6718 } else if (vr != null && vr.IsRef) {
6722 if (arguments != null) {
6723 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6724 arguments = arguments.Emit (ec, false, true);
6726 arguments.Emit (ec);
6729 if (is_value_type) {
6730 if (method == null) {
6731 ec.Emit (OpCodes.Initobj, type);
6736 ec.MarkCallEntry (loc);
6737 ec.Emit (OpCodes.Call, method);
6742 if (type is TypeParameterSpec)
6743 return DoEmitTypeParameter (ec);
6745 ec.MarkCallEntry (loc);
6746 ec.Emit (OpCodes.Newobj, method);
6750 public override void Emit (EmitContext ec)
6752 LocalTemporary v = null;
6753 if (method == null && TypeSpec.IsValueType (type)) {
6754 // TODO: Use temporary variable from pool
6755 v = new LocalTemporary (type);
6762 public override void EmitStatement (EmitContext ec)
6764 LocalTemporary v = null;
6765 if (method == null && TypeSpec.IsValueType (type)) {
6766 // TODO: Use temporary variable from pool
6767 v = new LocalTemporary (type);
6771 ec.Emit (OpCodes.Pop);
6774 public override void FlowAnalysis (FlowAnalysisContext fc)
6776 if (arguments != null)
6777 arguments.FlowAnalysis (fc);
6780 public void AddressOf (EmitContext ec, AddressOp mode)
6782 EmitAddressOf (ec, mode);
6785 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6787 LocalTemporary value_target = new LocalTemporary (type);
6789 if (type is TypeParameterSpec) {
6790 DoEmitTypeParameter (ec);
6791 value_target.Store (ec);
6792 value_target.AddressOf (ec, mode);
6793 return value_target;
6796 value_target.AddressOf (ec, AddressOp.Store);
6798 if (method == null) {
6799 ec.Emit (OpCodes.Initobj, type);
6801 if (arguments != null)
6802 arguments.Emit (ec);
6804 ec.Emit (OpCodes.Call, method);
6807 value_target.AddressOf (ec, mode);
6808 return value_target;
6811 protected override void CloneTo (CloneContext clonectx, Expression t)
6813 New target = (New) t;
6815 target.RequestedType = RequestedType.Clone (clonectx);
6816 if (arguments != null){
6817 target.arguments = arguments.Clone (clonectx);
6821 public override SLE.Expression MakeExpression (BuilderContext ctx)
6824 return base.MakeExpression (ctx);
6826 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6830 public override object Accept (StructuralVisitor visitor)
6832 return visitor.Visit (this);
6837 // Array initializer expression, the expression is allowed in
6838 // variable or field initialization only which makes it tricky as
6839 // the type has to be infered based on the context either from field
6840 // type or variable type (think of multiple declarators)
6842 public class ArrayInitializer : Expression
6844 List<Expression> elements;
6845 BlockVariable variable;
6847 public ArrayInitializer (List<Expression> init, Location loc)
6853 public ArrayInitializer (int count, Location loc)
6854 : this (new List<Expression> (count), loc)
6858 public ArrayInitializer (Location loc)
6866 get { return elements.Count; }
6869 public List<Expression> Elements {
6875 public Expression this [int index] {
6877 return elements [index];
6881 public BlockVariable VariableDeclaration {
6892 public void Add (Expression expr)
6894 elements.Add (expr);
6897 public override bool ContainsEmitWithAwait ()
6899 throw new NotSupportedException ();
6902 public override Expression CreateExpressionTree (ResolveContext ec)
6904 throw new NotSupportedException ("ET");
6907 protected override void CloneTo (CloneContext clonectx, Expression t)
6909 var target = (ArrayInitializer) t;
6911 target.elements = new List<Expression> (elements.Count);
6912 foreach (var element in elements)
6913 target.elements.Add (element.Clone (clonectx));
6916 protected override Expression DoResolve (ResolveContext rc)
6918 var current_field = rc.CurrentMemberDefinition as FieldBase;
6919 TypeExpression type;
6920 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6921 type = new TypeExpression (current_field.MemberType, current_field.Location);
6922 } else if (variable != null) {
6923 if (variable.TypeExpression is VarExpr) {
6924 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6925 return EmptyExpression.Null;
6928 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6930 throw new NotImplementedException ("Unexpected array initializer context");
6933 return new ArrayCreation (type, this).Resolve (rc);
6936 public override void Emit (EmitContext ec)
6938 throw new InternalErrorException ("Missing Resolve call");
6941 public override void FlowAnalysis (FlowAnalysisContext fc)
6943 throw new InternalErrorException ("Missing Resolve call");
6946 public override object Accept (StructuralVisitor visitor)
6948 return visitor.Visit (this);
6953 /// 14.5.10.2: Represents an array creation expression.
6957 /// There are two possible scenarios here: one is an array creation
6958 /// expression that specifies the dimensions and optionally the
6959 /// initialization data and the other which does not need dimensions
6960 /// specified but where initialization data is mandatory.
6962 public class ArrayCreation : Expression
6964 FullNamedExpression requested_base_type;
6965 ArrayInitializer initializers;
6968 // The list of Argument types.
6969 // This is used to construct the `newarray' or constructor signature
6971 protected List<Expression> arguments;
6973 protected TypeSpec array_element_type;
6975 protected int dimensions;
6976 protected readonly ComposedTypeSpecifier rank;
6977 Expression first_emit;
6978 LocalTemporary first_emit_temp;
6980 protected List<Expression> array_data;
6982 Dictionary<int, int> bounds;
6985 // The number of constants in array initializers
6986 int const_initializers_count;
6987 bool only_constant_initializers;
6989 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6990 : this (requested_base_type, rank, initializers, l)
6992 arguments = new List<Expression> (exprs);
6993 num_arguments = arguments.Count;
6997 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6999 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7001 this.requested_base_type = requested_base_type;
7003 this.initializers = initializers;
7007 num_arguments = rank.Dimension;
7011 // For compiler generated single dimensional arrays only
7013 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7014 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7019 // For expressions like int[] foo = { 1, 2, 3 };
7021 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7022 : this (requested_base_type, null, initializers, initializers.Location)
7026 public ComposedTypeSpecifier Rank {
7032 public FullNamedExpression TypeExpression {
7034 return this.requested_base_type;
7038 public ArrayInitializer Initializers {
7040 return this.initializers;
7044 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7046 if (initializers != null && bounds == null) {
7048 // We use this to store all the data values in the order in which we
7049 // will need to store them in the byte blob later
7051 array_data = new List<Expression> (probe.Count);
7052 bounds = new Dictionary<int, int> ();
7055 if (specified_dims) {
7056 Expression a = arguments [idx];
7061 a = ConvertExpressionToArrayIndex (ec, a);
7067 if (initializers != null) {
7068 Constant c = a as Constant;
7069 if (c == null && a is ArrayIndexCast)
7070 c = ((ArrayIndexCast) a).Child as Constant;
7073 ec.Report.Error (150, a.Location, "A constant value is expected");
7079 value = System.Convert.ToInt32 (c.GetValue ());
7081 ec.Report.Error (150, a.Location, "A constant value is expected");
7085 // TODO: probe.Count does not fit ulong in
7086 if (value != probe.Count) {
7087 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7091 bounds[idx] = value;
7095 if (initializers == null)
7098 for (int i = 0; i < probe.Count; ++i) {
7100 if (o is ArrayInitializer) {
7101 var sub_probe = o as ArrayInitializer;
7102 if (idx + 1 >= dimensions){
7103 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7107 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7108 if (!bounds.ContainsKey(idx + 1))
7109 bounds[idx + 1] = sub_probe.Count;
7111 if (bounds[idx + 1] != sub_probe.Count) {
7112 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7116 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7119 } else if (child_bounds > 1) {
7120 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7122 Expression element = ResolveArrayElement (ec, o);
7123 if (element == null)
7126 // Initializers with the default values can be ignored
7127 Constant c = element as Constant;
7129 if (!c.IsDefaultInitializer (array_element_type)) {
7130 ++const_initializers_count;
7133 only_constant_initializers = false;
7136 array_data.Add (element);
7143 public override bool ContainsEmitWithAwait ()
7145 foreach (var arg in arguments) {
7146 if (arg.ContainsEmitWithAwait ())
7150 return InitializersContainAwait ();
7153 public override Expression CreateExpressionTree (ResolveContext ec)
7157 if (array_data == null) {
7158 args = new Arguments (arguments.Count + 1);
7159 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7160 foreach (Expression a in arguments)
7161 args.Add (new Argument (a.CreateExpressionTree (ec)));
7163 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7166 if (dimensions > 1) {
7167 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7171 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7172 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7173 if (array_data != null) {
7174 for (int i = 0; i < array_data.Count; ++i) {
7175 Expression e = array_data [i];
7176 args.Add (new Argument (e.CreateExpressionTree (ec)));
7180 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7183 void UpdateIndices (ResolveContext rc)
7186 for (var probe = initializers; probe != null;) {
7187 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7189 bounds[i++] = probe.Count;
7191 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7192 probe = (ArrayInitializer) probe[0];
7193 } else if (dimensions > i) {
7201 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7203 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7206 public override void FlowAnalysis (FlowAnalysisContext fc)
7208 foreach (var arg in arguments)
7209 arg.FlowAnalysis (fc);
7211 if (array_data != null) {
7212 foreach (var ad in array_data)
7213 ad.FlowAnalysis (fc);
7217 bool InitializersContainAwait ()
7219 if (array_data == null)
7222 foreach (var expr in array_data) {
7223 if (expr.ContainsEmitWithAwait ())
7230 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7232 element = element.Resolve (ec);
7233 if (element == null)
7236 if (element is CompoundAssign.TargetExpression) {
7237 if (first_emit != null)
7238 throw new InternalErrorException ("Can only handle one mutator at a time");
7239 first_emit = element;
7240 element = first_emit_temp = new LocalTemporary (element.Type);
7243 return Convert.ImplicitConversionRequired (
7244 ec, element, array_element_type, loc);
7247 protected bool ResolveInitializers (ResolveContext ec)
7250 only_constant_initializers = true;
7253 if (arguments != null) {
7255 for (int i = 0; i < arguments.Count; ++i) {
7256 res &= CheckIndices (ec, initializers, i, true, dimensions);
7257 if (initializers != null)
7264 arguments = new List<Expression> ();
7266 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7275 // Resolved the type of the array
7277 bool ResolveArrayType (ResolveContext ec)
7282 FullNamedExpression array_type_expr;
7283 if (num_arguments > 0) {
7284 array_type_expr = new ComposedCast (requested_base_type, rank);
7286 array_type_expr = requested_base_type;
7289 type = array_type_expr.ResolveAsType (ec);
7290 if (array_type_expr == null)
7293 var ac = type as ArrayContainer;
7295 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7299 array_element_type = ac.Element;
7300 dimensions = ac.Rank;
7305 protected override Expression DoResolve (ResolveContext ec)
7310 if (!ResolveArrayType (ec))
7314 // validate the initializers and fill in any missing bits
7316 if (!ResolveInitializers (ec))
7319 eclass = ExprClass.Value;
7323 byte [] MakeByteBlob ()
7328 int count = array_data.Count;
7330 TypeSpec element_type = array_element_type;
7331 if (element_type.IsEnum)
7332 element_type = EnumSpec.GetUnderlyingType (element_type);
7334 factor = BuiltinTypeSpec.GetSize (element_type);
7336 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7338 data = new byte [(count * factor + 3) & ~3];
7341 for (int i = 0; i < count; ++i) {
7342 var c = array_data[i] as Constant;
7348 object v = c.GetValue ();
7350 switch (element_type.BuiltinType) {
7351 case BuiltinTypeSpec.Type.Long:
7352 long lval = (long) v;
7354 for (int j = 0; j < factor; ++j) {
7355 data[idx + j] = (byte) (lval & 0xFF);
7359 case BuiltinTypeSpec.Type.ULong:
7360 ulong ulval = (ulong) v;
7362 for (int j = 0; j < factor; ++j) {
7363 data[idx + j] = (byte) (ulval & 0xFF);
7364 ulval = (ulval >> 8);
7367 case BuiltinTypeSpec.Type.Float:
7368 var fval = SingleConverter.SingleToInt32Bits((float) v);
7370 data[idx] = (byte) (fval & 0xff);
7371 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7372 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7373 data[idx + 3] = (byte) (fval >> 24);
7375 case BuiltinTypeSpec.Type.Double:
7376 element = BitConverter.GetBytes ((double) v);
7378 for (int j = 0; j < factor; ++j)
7379 data[idx + j] = element[j];
7381 // FIXME: Handle the ARM float format.
7382 if (!BitConverter.IsLittleEndian)
7383 System.Array.Reverse (data, idx, 8);
7385 case BuiltinTypeSpec.Type.Char:
7386 int chval = (int) ((char) v);
7388 data[idx] = (byte) (chval & 0xff);
7389 data[idx + 1] = (byte) (chval >> 8);
7391 case BuiltinTypeSpec.Type.Short:
7392 int sval = (int) ((short) v);
7394 data[idx] = (byte) (sval & 0xff);
7395 data[idx + 1] = (byte) (sval >> 8);
7397 case BuiltinTypeSpec.Type.UShort:
7398 int usval = (int) ((ushort) v);
7400 data[idx] = (byte) (usval & 0xff);
7401 data[idx + 1] = (byte) (usval >> 8);
7403 case BuiltinTypeSpec.Type.Int:
7406 data[idx] = (byte) (val & 0xff);
7407 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7408 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7409 data[idx + 3] = (byte) (val >> 24);
7411 case BuiltinTypeSpec.Type.UInt:
7412 uint uval = (uint) v;
7414 data[idx] = (byte) (uval & 0xff);
7415 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7416 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7417 data[idx + 3] = (byte) (uval >> 24);
7419 case BuiltinTypeSpec.Type.SByte:
7420 data[idx] = (byte) (sbyte) v;
7422 case BuiltinTypeSpec.Type.Byte:
7423 data[idx] = (byte) v;
7425 case BuiltinTypeSpec.Type.Bool:
7426 data[idx] = (byte) ((bool) v ? 1 : 0);
7428 case BuiltinTypeSpec.Type.Decimal:
7429 int[] bits = Decimal.GetBits ((decimal) v);
7432 // FIXME: For some reason, this doesn't work on the MS runtime.
7433 int[] nbits = new int[4];
7439 for (int j = 0; j < 4; j++) {
7440 data[p++] = (byte) (nbits[j] & 0xff);
7441 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7442 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7443 data[p++] = (byte) (nbits[j] >> 24);
7447 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7456 #if NET_4_0 || MOBILE_DYNAMIC
7457 public override SLE.Expression MakeExpression (BuilderContext ctx)
7460 return base.MakeExpression (ctx);
7462 var initializers = new SLE.Expression [array_data.Count];
7463 for (var i = 0; i < initializers.Length; i++) {
7464 if (array_data [i] == null)
7465 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7467 initializers [i] = array_data [i].MakeExpression (ctx);
7470 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7476 // Emits the initializers for the array
7478 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7480 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7485 // First, the static data
7487 byte [] data = MakeByteBlob ();
7488 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7490 if (stackArray == null) {
7491 ec.Emit (OpCodes.Dup);
7493 stackArray.Emit (ec);
7496 ec.Emit (OpCodes.Ldtoken, fb);
7497 ec.Emit (OpCodes.Call, m);
7502 // Emits pieces of the array that can not be computed at compile
7503 // time (variables and string locations).
7505 // This always expect the top value on the stack to be the array
7507 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
7509 int dims = bounds.Count;
7510 var current_pos = new int [dims];
7512 for (int i = 0; i < array_data.Count; i++){
7514 Expression e = array_data [i];
7515 var c = e as Constant;
7517 // Constant can be initialized via StaticInitializer
7518 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7522 if (stackArray != null) {
7523 if (e.ContainsEmitWithAwait ()) {
7524 e = e.EmitToField (ec);
7527 stackArray.EmitLoad (ec);
7529 ec.Emit (OpCodes.Dup);
7532 for (int idx = 0; idx < dims; idx++)
7533 ec.EmitInt (current_pos [idx]);
7536 // If we are dealing with a struct, get the
7537 // address of it, so we can store it.
7539 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
7540 ec.Emit (OpCodes.Ldelema, etype);
7544 ec.EmitArrayStore ((ArrayContainer) type);
7550 for (int j = dims - 1; j >= 0; j--){
7552 if (current_pos [j] < bounds [j])
7554 current_pos [j] = 0;
7558 if (stackArray != null)
7559 stackArray.PrepareCleanup (ec);
7562 public override void Emit (EmitContext ec)
7564 EmitToFieldSource (ec);
7567 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7569 if (first_emit != null) {
7570 first_emit.Emit (ec);
7571 first_emit_temp.Store (ec);
7574 StackFieldExpr await_stack_field;
7575 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7576 await_stack_field = ec.GetTemporaryField (type);
7579 await_stack_field = null;
7582 EmitExpressionsList (ec, arguments);
7584 ec.EmitArrayNew ((ArrayContainer) type);
7586 if (initializers == null)
7587 return await_stack_field;
7589 if (await_stack_field != null)
7590 await_stack_field.EmitAssignFromStack (ec);
7594 // Emit static initializer for arrays which contain more than 2 items and
7595 // the static initializer will initialize at least 25% of array values or there
7596 // is more than 10 items to be initialized
7598 // NOTE: const_initializers_count does not contain default constant values.
7600 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7601 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7602 EmitStaticInitializers (ec, await_stack_field);
7604 if (!only_constant_initializers)
7605 EmitDynamicInitializers (ec, false, await_stack_field);
7609 EmitDynamicInitializers (ec, true, await_stack_field);
7612 if (first_emit_temp != null)
7613 first_emit_temp.Release (ec);
7615 return await_stack_field;
7618 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7620 // no multi dimensional or jagged arrays
7621 if (arguments.Count != 1 || array_element_type.IsArray) {
7622 base.EncodeAttributeValue (rc, enc, targetType);
7626 // No array covariance, except for array -> object
7627 if (type != targetType) {
7628 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7629 base.EncodeAttributeValue (rc, enc, targetType);
7633 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7634 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7639 // Single dimensional array of 0 size
7640 if (array_data == null) {
7641 IntConstant ic = arguments[0] as IntConstant;
7642 if (ic == null || !ic.IsDefaultValue) {
7643 base.EncodeAttributeValue (rc, enc, targetType);
7651 enc.Encode (array_data.Count);
7652 foreach (var element in array_data) {
7653 element.EncodeAttributeValue (rc, enc, array_element_type);
7657 protected override void CloneTo (CloneContext clonectx, Expression t)
7659 ArrayCreation target = (ArrayCreation) t;
7661 if (requested_base_type != null)
7662 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7664 if (arguments != null){
7665 target.arguments = new List<Expression> (arguments.Count);
7666 foreach (Expression e in arguments)
7667 target.arguments.Add (e.Clone (clonectx));
7670 if (initializers != null)
7671 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7674 public override object Accept (StructuralVisitor visitor)
7676 return visitor.Visit (this);
7681 // Represents an implicitly typed array epxression
7683 class ImplicitlyTypedArrayCreation : ArrayCreation
7685 TypeInferenceContext best_type_inference;
7687 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7688 : base (null, rank, initializers, loc)
7692 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7693 : base (null, initializers, loc)
7697 protected override Expression DoResolve (ResolveContext ec)
7702 dimensions = rank.Dimension;
7704 best_type_inference = new TypeInferenceContext ();
7706 if (!ResolveInitializers (ec))
7709 best_type_inference.FixAllTypes (ec);
7710 array_element_type = best_type_inference.InferredTypeArguments[0];
7711 best_type_inference = null;
7713 if (array_element_type == null ||
7714 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7715 arguments.Count != rank.Dimension) {
7716 ec.Report.Error (826, loc,
7717 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7722 // At this point we found common base type for all initializer elements
7723 // but we have to be sure that all static initializer elements are of
7726 UnifyInitializerElement (ec);
7728 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7729 eclass = ExprClass.Value;
7734 // Converts static initializer only
7736 void UnifyInitializerElement (ResolveContext ec)
7738 for (int i = 0; i < array_data.Count; ++i) {
7739 Expression e = array_data[i];
7741 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7745 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7747 element = element.Resolve (ec);
7748 if (element != null)
7749 best_type_inference.AddCommonTypeBound (element.Type);
7755 sealed class CompilerGeneratedThis : This
7757 public CompilerGeneratedThis (TypeSpec type, Location loc)
7761 eclass = ExprClass.Variable;
7764 protected override Expression DoResolve (ResolveContext ec)
7769 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7776 /// Represents the `this' construct
7779 public class This : VariableReference
7781 sealed class ThisVariable : ILocalVariable
7783 public static readonly ILocalVariable Instance = new ThisVariable ();
7785 public void Emit (EmitContext ec)
7790 public void EmitAssign (EmitContext ec)
7792 throw new InvalidOperationException ();
7795 public void EmitAddressOf (EmitContext ec)
7801 VariableInfo variable_info;
7803 public This (Location loc)
7810 public override string Name {
7811 get { return "this"; }
7814 public override bool IsLockedByStatement {
7822 public override bool IsRef {
7823 get { return type.IsStruct; }
7826 public override bool IsSideEffectFree {
7832 protected override ILocalVariable Variable {
7833 get { return ThisVariable.Instance; }
7836 public override VariableInfo VariableInfo {
7837 get { return variable_info; }
7840 public override bool IsFixed {
7841 get { return false; }
7846 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
7849 // It's null for all cases when we don't need to check `this'
7850 // definitive assignment
7852 if (variable_info == null)
7855 if (fc.IsDefinitelyAssigned (variable_info))
7858 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
7861 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7863 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7864 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7865 } else if (ec.CurrentAnonymousMethod != null) {
7866 ec.Report.Error (1673, loc,
7867 "Anonymous methods inside structs cannot access instance members of `this'. " +
7868 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7870 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7874 public override void FlowAnalysis (FlowAnalysisContext fc)
7876 CheckStructThisDefiniteAssignment (fc);
7879 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7884 AnonymousMethodStorey storey = ae.Storey;
7885 return storey != null ? storey.HoistedThis : null;
7888 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7890 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7893 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7896 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7902 public virtual void ResolveBase (ResolveContext ec)
7904 eclass = ExprClass.Variable;
7905 type = ec.CurrentType;
7907 if (!IsThisAvailable (ec, false)) {
7908 Error_ThisNotAvailable (ec);
7912 var block = ec.CurrentBlock;
7913 if (block != null) {
7914 var top = block.ParametersBlock.TopBlock;
7915 if (top.ThisVariable != null)
7916 variable_info = top.ThisVariable.VariableInfo;
7918 AnonymousExpression am = ec.CurrentAnonymousMethod;
7919 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7921 // Hoisted this is almost like hoisted variable but not exactly. When
7922 // there is no variable hoisted we can simply emit an instance method
7923 // without lifting this into a storey. Unfotunatelly this complicates
7924 // things in other cases because we don't know where this will be hoisted
7925 // until top-level block is fully resolved
7927 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7928 am.SetHasThisAccess ();
7933 protected override Expression DoResolve (ResolveContext ec)
7939 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7941 if (eclass == ExprClass.Unresolved)
7945 if (right_side == EmptyExpression.UnaryAddress)
7946 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7947 else if (right_side == EmptyExpression.OutAccess)
7948 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7950 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7956 public override int GetHashCode()
7958 throw new NotImplementedException ();
7961 public override bool Equals (object obj)
7963 This t = obj as This;
7970 protected override void CloneTo (CloneContext clonectx, Expression t)
7975 public override void SetHasAddressTaken ()
7980 public override object Accept (StructuralVisitor visitor)
7982 return visitor.Visit (this);
7987 /// Represents the `__arglist' construct
7989 public class ArglistAccess : Expression
7991 public ArglistAccess (Location loc)
7996 protected override void CloneTo (CloneContext clonectx, Expression target)
8001 public override bool ContainsEmitWithAwait ()
8006 public override Expression CreateExpressionTree (ResolveContext ec)
8008 throw new NotSupportedException ("ET");
8011 protected override Expression DoResolve (ResolveContext ec)
8013 eclass = ExprClass.Variable;
8014 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8016 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8017 ec.Report.Error (190, loc,
8018 "The __arglist construct is valid only within a variable argument method");
8024 public override void Emit (EmitContext ec)
8026 ec.Emit (OpCodes.Arglist);
8029 public override object Accept (StructuralVisitor visitor)
8031 return visitor.Visit (this);
8036 /// Represents the `__arglist (....)' construct
8038 public class Arglist : Expression
8040 Arguments arguments;
8042 public Arglist (Location loc)
8047 public Arglist (Arguments args, Location l)
8053 public Arguments Arguments {
8059 public MetaType[] ArgumentTypes {
8061 if (arguments == null)
8062 return MetaType.EmptyTypes;
8064 var retval = new MetaType[arguments.Count];
8065 for (int i = 0; i < retval.Length; i++)
8066 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8072 public override bool ContainsEmitWithAwait ()
8074 throw new NotImplementedException ();
8077 public override Expression CreateExpressionTree (ResolveContext ec)
8079 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8083 protected override Expression DoResolve (ResolveContext ec)
8085 eclass = ExprClass.Variable;
8086 type = InternalType.Arglist;
8087 if (arguments != null) {
8088 bool dynamic; // Can be ignored as there is always only 1 overload
8089 arguments.Resolve (ec, out dynamic);
8095 public override void Emit (EmitContext ec)
8097 if (arguments != null)
8098 arguments.Emit (ec);
8101 protected override void CloneTo (CloneContext clonectx, Expression t)
8103 Arglist target = (Arglist) t;
8105 if (arguments != null)
8106 target.arguments = arguments.Clone (clonectx);
8109 public override object Accept (StructuralVisitor visitor)
8111 return visitor.Visit (this);
8115 public class RefValueExpr : ShimExpression, IAssignMethod
8117 FullNamedExpression texpr;
8119 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8126 public FullNamedExpression TypeExpression {
8132 public override bool ContainsEmitWithAwait ()
8137 protected override Expression DoResolve (ResolveContext rc)
8139 expr = expr.Resolve (rc);
8140 type = texpr.ResolveAsType (rc);
8141 if (expr == null || type == null)
8144 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8145 eclass = ExprClass.Value;
8149 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8151 return DoResolve (rc);
8154 public override void Emit (EmitContext ec)
8157 ec.Emit (OpCodes.Refanyval, type);
8158 ec.EmitLoadFromPtr (type);
8161 public void Emit (EmitContext ec, bool leave_copy)
8163 throw new NotImplementedException ();
8166 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8169 ec.Emit (OpCodes.Refanyval, type);
8172 LocalTemporary temporary = null;
8174 ec.Emit (OpCodes.Dup);
8175 temporary = new LocalTemporary (source.Type);
8176 temporary.Store (ec);
8179 ec.EmitStoreFromPtr (type);
8181 if (temporary != null) {
8182 temporary.Emit (ec);
8183 temporary.Release (ec);
8187 public override object Accept (StructuralVisitor visitor)
8189 return visitor.Visit (this);
8193 public class RefTypeExpr : ShimExpression
8195 public RefTypeExpr (Expression expr, Location loc)
8201 protected override Expression DoResolve (ResolveContext rc)
8203 expr = expr.Resolve (rc);
8207 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8211 type = rc.BuiltinTypes.Type;
8212 eclass = ExprClass.Value;
8216 public override void Emit (EmitContext ec)
8219 ec.Emit (OpCodes.Refanytype);
8220 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8222 ec.Emit (OpCodes.Call, m);
8225 public override object Accept (StructuralVisitor visitor)
8227 return visitor.Visit (this);
8231 public class MakeRefExpr : ShimExpression
8233 public MakeRefExpr (Expression expr, Location loc)
8239 public override bool ContainsEmitWithAwait ()
8241 throw new NotImplementedException ();
8244 protected override Expression DoResolve (ResolveContext rc)
8246 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8247 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8248 eclass = ExprClass.Value;
8252 public override void Emit (EmitContext ec)
8254 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8255 ec.Emit (OpCodes.Mkrefany, expr.Type);
8258 public override object Accept (StructuralVisitor visitor)
8260 return visitor.Visit (this);
8265 /// Implements the typeof operator
8267 public class TypeOf : Expression {
8268 FullNamedExpression QueriedType;
8271 public TypeOf (FullNamedExpression queried_type, Location l)
8273 QueriedType = queried_type;
8278 // Use this constructor for any compiler generated typeof expression
8280 public TypeOf (TypeSpec type, Location loc)
8282 this.typearg = type;
8288 public override bool IsSideEffectFree {
8294 public TypeSpec TypeArgument {
8300 public FullNamedExpression TypeExpression {
8309 protected override void CloneTo (CloneContext clonectx, Expression t)
8311 TypeOf target = (TypeOf) t;
8312 if (QueriedType != null)
8313 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8316 public override bool ContainsEmitWithAwait ()
8321 public override Expression CreateExpressionTree (ResolveContext ec)
8323 Arguments args = new Arguments (2);
8324 args.Add (new Argument (this));
8325 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8326 return CreateExpressionFactoryCall (ec, "Constant", args);
8329 protected override Expression DoResolve (ResolveContext ec)
8331 if (eclass != ExprClass.Unresolved)
8334 if (typearg == null) {
8336 // Pointer types are allowed without explicit unsafe, they are just tokens
8338 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8339 typearg = QueriedType.ResolveAsType (ec);
8342 if (typearg == null)
8345 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8346 ec.Report.Error (1962, QueriedType.Location,
8347 "The typeof operator cannot be used on the dynamic type");
8351 type = ec.BuiltinTypes.Type;
8353 // Even though what is returned is a type object, it's treated as a value by the compiler.
8354 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8355 eclass = ExprClass.Value;
8359 static bool ContainsDynamicType (TypeSpec type)
8361 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8364 var element_container = type as ElementTypeSpec;
8365 if (element_container != null)
8366 return ContainsDynamicType (element_container.Element);
8368 foreach (var t in type.TypeArguments) {
8369 if (ContainsDynamicType (t)) {
8377 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8379 // Target type is not System.Type therefore must be object
8380 // and we need to use different encoding sequence
8381 if (targetType != type)
8384 if (typearg is InflatedTypeSpec) {
8387 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8388 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8389 typearg.GetSignatureForError ());
8393 gt = gt.DeclaringType;
8394 } while (gt != null);
8397 if (ContainsDynamicType (typearg)) {
8398 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8402 enc.EncodeTypeName (typearg);
8405 public override void Emit (EmitContext ec)
8407 ec.Emit (OpCodes.Ldtoken, typearg);
8408 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8410 ec.Emit (OpCodes.Call, m);
8413 public override object Accept (StructuralVisitor visitor)
8415 return visitor.Visit (this);
8419 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8421 public TypeOfMethod (MethodSpec method, Location loc)
8422 : base (method, loc)
8426 protected override Expression DoResolve (ResolveContext ec)
8428 if (member.IsConstructor) {
8429 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8431 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8437 return base.DoResolve (ec);
8440 public override void Emit (EmitContext ec)
8442 ec.Emit (OpCodes.Ldtoken, member);
8445 ec.Emit (OpCodes.Castclass, type);
8448 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8450 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8453 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8455 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8459 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8461 protected readonly T member;
8463 protected TypeOfMember (T member, Location loc)
8465 this.member = member;
8469 public override bool IsSideEffectFree {
8475 public override bool ContainsEmitWithAwait ()
8480 public override Expression CreateExpressionTree (ResolveContext ec)
8482 Arguments args = new Arguments (2);
8483 args.Add (new Argument (this));
8484 args.Add (new Argument (new TypeOf (type, loc)));
8485 return CreateExpressionFactoryCall (ec, "Constant", args);
8488 protected override Expression DoResolve (ResolveContext ec)
8490 eclass = ExprClass.Value;
8494 public override void Emit (EmitContext ec)
8496 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8497 PredefinedMember<MethodSpec> p;
8499 p = GetTypeFromHandleGeneric (ec);
8500 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8502 p = GetTypeFromHandle (ec);
8505 var mi = p.Resolve (loc);
8507 ec.Emit (OpCodes.Call, mi);
8510 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8511 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8514 sealed class TypeOfField : TypeOfMember<FieldSpec>
8516 public TypeOfField (FieldSpec field, Location loc)
8521 protected override Expression DoResolve (ResolveContext ec)
8523 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8527 return base.DoResolve (ec);
8530 public override void Emit (EmitContext ec)
8532 ec.Emit (OpCodes.Ldtoken, member);
8536 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8538 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8541 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8543 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8548 /// Implements the sizeof expression
8550 public class SizeOf : Expression {
8551 readonly Expression texpr;
8552 TypeSpec type_queried;
8554 public SizeOf (Expression queried_type, Location l)
8556 this.texpr = queried_type;
8560 public override bool IsSideEffectFree {
8566 public Expression TypeExpression {
8572 public override bool ContainsEmitWithAwait ()
8577 public override Expression CreateExpressionTree (ResolveContext ec)
8579 Error_PointerInsideExpressionTree (ec);
8583 protected override Expression DoResolve (ResolveContext ec)
8585 type_queried = texpr.ResolveAsType (ec);
8586 if (type_queried == null)
8589 if (type_queried.IsEnum)
8590 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8592 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8594 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8597 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8602 ec.Report.Error (233, loc,
8603 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8604 type_queried.GetSignatureForError ());
8607 type = ec.BuiltinTypes.Int;
8608 eclass = ExprClass.Value;
8612 public override void Emit (EmitContext ec)
8614 ec.Emit (OpCodes.Sizeof, type_queried);
8617 protected override void CloneTo (CloneContext clonectx, Expression t)
8621 public override object Accept (StructuralVisitor visitor)
8623 return visitor.Visit (this);
8628 /// Implements the qualified-alias-member (::) expression.
8630 public class QualifiedAliasMember : MemberAccess
8632 readonly string alias;
8633 public static readonly string GlobalAlias = "global";
8635 public QualifiedAliasMember (string alias, string identifier, Location l)
8636 : base (null, identifier, l)
8641 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8642 : base (null, identifier, targs, l)
8647 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8648 : base (null, identifier, arity, l)
8653 public string Alias {
8659 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8661 if (alias == GlobalAlias) {
8662 expr = new NamespaceExpression (ec.Module.GlobalRootNamespace, loc);
8663 return base.ResolveAsTypeOrNamespace (ec);
8666 int errors = ec.Module.Compiler.Report.Errors;
8667 expr = ec.LookupNamespaceAlias (alias);
8669 if (errors == ec.Module.Compiler.Report.Errors)
8670 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8674 return base.ResolveAsTypeOrNamespace (ec);
8677 protected override Expression DoResolve (ResolveContext ec)
8679 return ResolveAsTypeOrNamespace (ec);
8682 public override string GetSignatureForError ()
8685 if (targs != null) {
8686 name = Name + "<" + targs.GetSignatureForError () + ">";
8689 return alias + "::" + name;
8692 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8694 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8695 rc.Module.Compiler.Report.Error (687, loc,
8696 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8697 GetSignatureForError ());
8702 return DoResolve (rc);
8705 protected override void CloneTo (CloneContext clonectx, Expression t)
8710 public override object Accept (StructuralVisitor visitor)
8712 return visitor.Visit (this);
8717 /// Implements the member access expression
8719 public class MemberAccess : ATypeNameExpression
8721 protected Expression expr;
8723 public MemberAccess (Expression expr, string id)
8724 : base (id, expr.Location)
8729 public MemberAccess (Expression expr, string identifier, Location loc)
8730 : base (identifier, loc)
8735 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8736 : base (identifier, args, loc)
8741 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8742 : base (identifier, arity, loc)
8747 public Expression LeftExpression {
8753 public override Location StartLocation {
8755 return expr == null ? loc : expr.StartLocation;
8759 protected override Expression DoResolve (ResolveContext rc)
8761 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
8763 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8768 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8770 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
8772 if (e is TypeExpr) {
8773 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8778 e = e.ResolveLValue (rc, rhs);
8783 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8785 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8786 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8788 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8791 public static bool IsValidDotExpression (TypeSpec type)
8793 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8794 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8796 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8799 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8801 var sn = expr as SimpleName;
8802 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8805 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8808 // Resolve expression which does have type set as we need expression type
8809 // with disable flow analysis as we don't know whether left side expression
8810 // is used as variable or type
8812 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8813 expr = expr.Resolve (rc);
8814 } else if (expr is TypeParameterExpr) {
8815 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8819 expr = expr.Resolve (rc, flags);
8825 var ns = expr as NamespaceExpression;
8827 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8829 if (retval == null) {
8830 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8834 if (HasTypeArguments)
8835 return new GenericTypeExpr (retval.Type, targs, loc);
8841 TypeSpec expr_type = expr.Type;
8842 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8843 me = expr as MemberExpr;
8845 me.ResolveInstanceExpression (rc, null);
8847 Arguments args = new Arguments (1);
8848 args.Add (new Argument (expr));
8849 return new DynamicMemberBinder (Name, args, loc);
8852 if (!IsValidDotExpression (expr_type)) {
8853 Error_OperatorCannotBeApplied (rc, expr_type);
8857 var lookup_arity = Arity;
8858 bool errorMode = false;
8859 Expression member_lookup;
8861 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8862 if (member_lookup == null) {
8864 // Try to look for extension method when member lookup failed
8866 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8867 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8868 if (methods != null) {
8869 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8870 if (HasTypeArguments) {
8871 if (!targs.Resolve (rc))
8874 emg.SetTypeArguments (rc, targs);
8877 // TODO: it should really skip the checks bellow
8878 return emg.Resolve (rc);
8884 if (member_lookup == null) {
8885 var dep = expr_type.GetMissingDependencies ();
8887 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8888 } else if (expr is TypeExpr) {
8889 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8891 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8897 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8898 // Leave it to overload resolution to report correct error
8899 } else if (!(member_lookup is TypeExpr)) {
8900 // TODO: rc.SymbolRelatedToPreviousError
8901 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8906 if (member_lookup != null)
8910 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8914 TypeExpr texpr = member_lookup as TypeExpr;
8915 if (texpr != null) {
8916 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8917 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8918 Name, texpr.GetSignatureForError ());
8921 if (!texpr.Type.IsAccessible (rc)) {
8922 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8923 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8927 if (HasTypeArguments) {
8928 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8931 return member_lookup;
8934 me = member_lookup as MemberExpr;
8936 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8940 me = me.ResolveMemberAccess (rc, expr, sn);
8943 if (!targs.Resolve (rc))
8946 me.SetTypeArguments (rc, targs);
8952 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8954 FullNamedExpression fexpr = expr as FullNamedExpression;
8955 if (fexpr == null) {
8956 expr.ResolveAsType (rc);
8960 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8962 if (expr_resolved == null)
8965 var ns = expr_resolved as NamespaceExpression;
8967 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8969 if (retval == null) {
8970 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8971 } else if (HasTypeArguments) {
8972 retval = new GenericTypeExpr (retval.Type, targs, loc);
8973 if (retval.ResolveAsType (rc) == null)
8980 var tnew_expr = expr_resolved.ResolveAsType (rc);
8981 if (tnew_expr == null)
8984 TypeSpec expr_type = tnew_expr;
8985 if (TypeManager.IsGenericParameter (expr_type)) {
8986 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8987 tnew_expr.GetSignatureForError ());
8991 var qam = this as QualifiedAliasMember;
8993 rc.Module.Compiler.Report.Error (431, loc,
8994 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8999 TypeSpec nested = null;
9000 while (expr_type != null) {
9001 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9002 if (nested == null) {
9003 if (expr_type == tnew_expr) {
9004 Error_IdentifierNotFound (rc, expr_type, Name);
9008 expr_type = tnew_expr;
9009 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9010 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9014 if (nested.IsAccessible (rc))
9018 // Keep looking after inaccessible candidate but only if
9019 // we are not in same context as the definition itself
9021 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9024 expr_type = expr_type.BaseType;
9029 if (HasTypeArguments) {
9030 texpr = new GenericTypeExpr (nested, targs, loc);
9032 texpr = new GenericOpenTypeExpr (nested, loc);
9035 texpr = new TypeExpression (nested, loc);
9038 if (texpr.ResolveAsType (rc) == null)
9044 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
9046 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9048 if (nested != null) {
9049 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9053 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9054 if (any_other_member != null) {
9055 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9059 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9060 Name, expr_type.GetSignatureForError ());
9063 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9065 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9068 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9070 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9071 ec.Report.SymbolRelatedToPreviousError (type);
9073 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9075 // a using directive or an assembly reference
9077 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9079 missing = "an assembly reference";
9082 ec.Report.Error (1061, loc,
9083 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9084 type.GetSignatureForError (), name, missing);
9088 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9091 public override string GetSignatureForError ()
9093 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9096 protected override void CloneTo (CloneContext clonectx, Expression t)
9098 MemberAccess target = (MemberAccess) t;
9100 target.expr = expr.Clone (clonectx);
9103 public override object Accept (StructuralVisitor visitor)
9105 return visitor.Visit (this);
9110 /// Implements checked expressions
9112 public class CheckedExpr : Expression {
9114 public Expression Expr;
9116 public CheckedExpr (Expression e, Location l)
9122 public override bool ContainsEmitWithAwait ()
9124 return Expr.ContainsEmitWithAwait ();
9127 public override Expression CreateExpressionTree (ResolveContext ec)
9129 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9130 return Expr.CreateExpressionTree (ec);
9133 protected override Expression DoResolve (ResolveContext ec)
9135 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9136 Expr = Expr.Resolve (ec);
9141 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9144 eclass = Expr.eclass;
9149 public override void Emit (EmitContext ec)
9151 using (ec.With (EmitContext.Options.CheckedScope, true))
9155 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9157 using (ec.With (EmitContext.Options.CheckedScope, true))
9158 Expr.EmitBranchable (ec, target, on_true);
9161 public override void FlowAnalysis (FlowAnalysisContext fc)
9163 Expr.FlowAnalysis (fc);
9166 public override SLE.Expression MakeExpression (BuilderContext ctx)
9168 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9169 return Expr.MakeExpression (ctx);
9173 protected override void CloneTo (CloneContext clonectx, Expression t)
9175 CheckedExpr target = (CheckedExpr) t;
9177 target.Expr = Expr.Clone (clonectx);
9180 public override object Accept (StructuralVisitor visitor)
9182 return visitor.Visit (this);
9187 /// Implements the unchecked expression
9189 public class UnCheckedExpr : Expression {
9191 public Expression Expr;
9193 public UnCheckedExpr (Expression e, Location l)
9199 public override bool ContainsEmitWithAwait ()
9201 return Expr.ContainsEmitWithAwait ();
9204 public override Expression CreateExpressionTree (ResolveContext ec)
9206 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9207 return Expr.CreateExpressionTree (ec);
9210 protected override Expression DoResolve (ResolveContext ec)
9212 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9213 Expr = Expr.Resolve (ec);
9218 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9221 eclass = Expr.eclass;
9226 public override void Emit (EmitContext ec)
9228 using (ec.With (EmitContext.Options.CheckedScope, false))
9232 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9234 using (ec.With (EmitContext.Options.CheckedScope, false))
9235 Expr.EmitBranchable (ec, target, on_true);
9238 public override void FlowAnalysis (FlowAnalysisContext fc)
9240 Expr.FlowAnalysis (fc);
9243 protected override void CloneTo (CloneContext clonectx, Expression t)
9245 UnCheckedExpr target = (UnCheckedExpr) t;
9247 target.Expr = Expr.Clone (clonectx);
9250 public override object Accept (StructuralVisitor visitor)
9252 return visitor.Visit (this);
9257 /// An Element Access expression.
9259 /// During semantic analysis these are transformed into
9260 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9262 public class ElementAccess : Expression
9264 public Arguments Arguments;
9265 public Expression Expr;
9267 public ElementAccess (Expression e, Arguments args, Location loc)
9271 this.Arguments = args;
9274 public override Location StartLocation {
9276 return Expr.StartLocation;
9280 public override bool ContainsEmitWithAwait ()
9282 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9286 // We perform some simple tests, and then to "split" the emit and store
9287 // code we create an instance of a different class, and return that.
9289 Expression CreateAccessExpression (ResolveContext ec)
9292 return (new ArrayAccess (this, loc));
9295 return MakePointerAccess (ec, type);
9297 FieldExpr fe = Expr as FieldExpr;
9299 var ff = fe.Spec as FixedFieldSpec;
9301 return MakePointerAccess (ec, ff.ElementType);
9305 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9306 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9307 return new IndexerExpr (indexers, type, this);
9310 if (type != InternalType.ErrorType) {
9311 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9312 type.GetSignatureForError ());
9318 public override Expression CreateExpressionTree (ResolveContext ec)
9320 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9321 Expr.CreateExpressionTree (ec));
9323 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9326 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
9328 if (Arguments.Count != 1){
9329 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
9333 var arg = Arguments[0];
9334 if (arg is NamedArgument)
9335 Error_NamedArgument ((NamedArgument) arg, rc.Report);
9337 var index = arg.Expr.Resolve (rc);
9341 index = ConvertExpressionToArrayIndex (rc, index, true);
9343 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
9344 return new Indirection (p, loc);
9347 protected override Expression DoResolve (ResolveContext ec)
9349 Expr = Expr.Resolve (ec);
9355 // TODO: Create 1 result for Resolve and ResolveLValue ?
9356 var res = CreateAccessExpression (ec);
9360 return res.Resolve (ec);
9363 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9365 Expr = Expr.Resolve (ec);
9371 var res = CreateAccessExpression (ec);
9375 return res.ResolveLValue (ec, rhs);
9378 public override void Emit (EmitContext ec)
9380 throw new Exception ("Should never be reached");
9383 public static void Error_NamedArgument (NamedArgument na, Report Report)
9385 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9388 public override void FlowAnalysis (FlowAnalysisContext fc)
9390 Expr.FlowAnalysis (fc);
9391 Arguments.FlowAnalysis (fc);
9394 public override string GetSignatureForError ()
9396 return Expr.GetSignatureForError ();
9399 protected override void CloneTo (CloneContext clonectx, Expression t)
9401 ElementAccess target = (ElementAccess) t;
9403 target.Expr = Expr.Clone (clonectx);
9404 if (Arguments != null)
9405 target.Arguments = Arguments.Clone (clonectx);
9408 public override object Accept (StructuralVisitor visitor)
9410 return visitor.Visit (this);
9415 /// Implements array access
9417 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9419 // Points to our "data" repository
9423 LocalTemporary temp;
9425 bool? has_await_args;
9427 public ArrayAccess (ElementAccess ea_data, Location l)
9433 public void AddressOf (EmitContext ec, AddressOp mode)
9435 var ac = (ArrayContainer) ea.Expr.Type;
9437 LoadInstanceAndArguments (ec, false, false);
9439 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9440 ec.Emit (OpCodes.Readonly);
9442 ec.EmitArrayAddress (ac);
9445 public override Expression CreateExpressionTree (ResolveContext ec)
9447 return ea.CreateExpressionTree (ec);
9450 public override bool ContainsEmitWithAwait ()
9452 return ea.ContainsEmitWithAwait ();
9455 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9457 return DoResolve (ec);
9460 protected override Expression DoResolve (ResolveContext ec)
9462 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9464 ea.Arguments.Resolve (ec, out dynamic);
9466 var ac = ea.Expr.Type as ArrayContainer;
9467 int rank = ea.Arguments.Count;
9468 if (ac.Rank != rank) {
9469 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9470 rank.ToString (), ac.Rank.ToString ());
9475 if (type.IsPointer && !ec.IsUnsafe) {
9476 UnsafeError (ec, ea.Location);
9479 foreach (Argument a in ea.Arguments) {
9480 if (a is NamedArgument)
9481 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9483 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9486 eclass = ExprClass.Variable;
9491 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9493 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9496 public override void FlowAnalysis (FlowAnalysisContext fc)
9498 ea.FlowAnalysis (fc);
9502 // Load the array arguments into the stack.
9504 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9507 ea.Expr = ea.Expr.EmitToField (ec);
9508 } else if (duplicateArguments) {
9510 ec.Emit (OpCodes.Dup);
9512 var copy = new LocalTemporary (ea.Expr.Type);
9519 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9520 if (dup_args != null)
9521 ea.Arguments = dup_args;
9524 public void Emit (EmitContext ec, bool leave_copy)
9526 var ac = ea.Expr.Type as ArrayContainer;
9529 ec.EmitLoadFromPtr (type);
9531 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9532 LoadInstanceAndArguments (ec, false, true);
9535 LoadInstanceAndArguments (ec, false, false);
9536 ec.EmitArrayLoad (ac);
9540 ec.Emit (OpCodes.Dup);
9541 temp = new LocalTemporary (this.type);
9546 public override void Emit (EmitContext ec)
9551 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9553 var ac = (ArrayContainer) ea.Expr.Type;
9554 TypeSpec t = source.Type;
9556 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9559 // When we are dealing with a struct, get the address of it to avoid value copy
9560 // Same cannot be done for reference type because array covariance and the
9561 // check in ldelema requires to specify the type of array element stored at the index
9563 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9564 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9566 if (has_await_args.Value) {
9567 if (source.ContainsEmitWithAwait ()) {
9568 source = source.EmitToField (ec);
9573 LoadInstanceAndArguments (ec, isCompound, false);
9578 ec.EmitArrayAddress (ac);
9581 ec.Emit (OpCodes.Dup);
9585 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9587 if (has_await_args.Value) {
9588 if (source.ContainsEmitWithAwait ())
9589 source = source.EmitToField (ec);
9591 LoadInstanceAndArguments (ec, false, false);
9598 var lt = ea.Expr as LocalTemporary;
9604 ec.Emit (OpCodes.Dup);
9605 temp = new LocalTemporary (this.type);
9610 ec.EmitStoreFromPtr (t);
9612 ec.EmitArrayStore (ac);
9621 public override Expression EmitToField (EmitContext ec)
9624 // Have to be specialized for arrays to get access to
9625 // underlying element. Instead of another result copy we
9626 // need direct access to element
9630 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9632 ea.Expr = ea.Expr.EmitToField (ec);
9636 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9638 #if NET_4_0 || MOBILE_DYNAMIC
9639 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9641 throw new NotImplementedException ();
9645 public override SLE.Expression MakeExpression (BuilderContext ctx)
9647 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9650 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9652 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9653 return Arguments.MakeExpression (ea.Arguments, ctx);
9659 // Indexer access expression
9661 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9663 IList<MemberSpec> indexers;
9664 Arguments arguments;
9665 TypeSpec queried_type;
9667 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9668 : base (ea.Location)
9670 this.indexers = indexers;
9671 this.queried_type = queriedType;
9672 this.InstanceExpression = ea.Expr;
9673 this.arguments = ea.Arguments;
9678 protected override Arguments Arguments {
9687 protected override TypeSpec DeclaringType {
9689 return best_candidate.DeclaringType;
9693 public override bool IsInstance {
9699 public override bool IsStatic {
9705 public override string KindName {
9706 get { return "indexer"; }
9709 public override string Name {
9717 public override bool ContainsEmitWithAwait ()
9719 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9722 public override Expression CreateExpressionTree (ResolveContext ec)
9724 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9725 InstanceExpression.CreateExpressionTree (ec),
9726 new TypeOfMethod (Getter, loc));
9728 return CreateExpressionFactoryCall (ec, "Call", args);
9731 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9733 LocalTemporary await_source_arg = null;
9736 emitting_compound_assignment = true;
9737 if (source is DynamicExpressionStatement) {
9742 emitting_compound_assignment = false;
9744 if (has_await_arguments) {
9745 await_source_arg = new LocalTemporary (Type);
9746 await_source_arg.Store (ec);
9748 arguments.Add (new Argument (await_source_arg));
9751 temp = await_source_arg;
9754 has_await_arguments = false;
9759 ec.Emit (OpCodes.Dup);
9760 temp = new LocalTemporary (Type);
9766 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9767 source = source.EmitToField (ec);
9769 temp = new LocalTemporary (Type);
9776 arguments.Add (new Argument (source));
9779 var call = new CallEmitter ();
9780 call.InstanceExpression = InstanceExpression;
9781 if (arguments == null)
9782 call.InstanceExpressionOnStack = true;
9784 call.Emit (ec, Setter, arguments, loc);
9789 } else if (leave_copy) {
9793 if (await_source_arg != null) {
9794 await_source_arg.Release (ec);
9798 public override void FlowAnalysis (FlowAnalysisContext fc)
9800 // TODO: Check the order
9801 base.FlowAnalysis (fc);
9802 arguments.FlowAnalysis (fc);
9805 public override string GetSignatureForError ()
9807 return best_candidate.GetSignatureForError ();
9810 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9813 throw new NotSupportedException ();
9815 var value = new[] { source.MakeExpression (ctx) };
9816 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9817 #if NET_4_0 || MOBILE_DYNAMIC
9818 return SLE.Expression.Block (
9819 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9822 return args.First ();
9827 public override SLE.Expression MakeExpression (BuilderContext ctx)
9830 return base.MakeExpression (ctx);
9832 var args = Arguments.MakeExpression (arguments, ctx);
9833 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9837 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9839 if (best_candidate != null)
9842 eclass = ExprClass.IndexerAccess;
9845 arguments.Resolve (rc, out dynamic);
9847 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9850 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9851 res.BaseMembersProvider = this;
9852 res.InstanceQualifier = this;
9854 // TODO: Do I need 2 argument sets?
9855 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9856 if (best_candidate != null)
9857 type = res.BestCandidateReturnType;
9858 else if (!res.BestCandidateIsDynamic)
9863 // It has dynamic arguments
9866 Arguments args = new Arguments (arguments.Count + 1);
9868 rc.Report.Error (1972, loc,
9869 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9871 args.Add (new Argument (InstanceExpression));
9873 args.AddRange (arguments);
9875 best_candidate = null;
9876 return new DynamicIndexBinder (args, loc);
9880 // Try to avoid resolving left expression again
9882 if (right_side != null)
9883 ResolveInstanceExpression (rc, right_side);
9888 protected override void CloneTo (CloneContext clonectx, Expression t)
9890 IndexerExpr target = (IndexerExpr) t;
9892 if (arguments != null)
9893 target.arguments = arguments.Clone (clonectx);
9896 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9898 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9901 #region IBaseMembersProvider Members
9903 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9905 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9908 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9910 if (queried_type == member.DeclaringType)
9913 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9914 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9917 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9926 // A base access expression
9928 public class BaseThis : This
9930 public BaseThis (Location loc)
9935 public BaseThis (TypeSpec type, Location loc)
9939 eclass = ExprClass.Variable;
9944 public override string Name {
9952 public override Expression CreateExpressionTree (ResolveContext ec)
9954 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9955 return base.CreateExpressionTree (ec);
9958 public override void Emit (EmitContext ec)
9962 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
9963 var context_type = ec.CurrentType;
9964 ec.Emit (OpCodes.Ldobj, context_type);
9965 ec.Emit (OpCodes.Box, context_type);
9969 protected override void Error_ThisNotAvailable (ResolveContext ec)
9972 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9974 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9978 public override void ResolveBase (ResolveContext ec)
9980 base.ResolveBase (ec);
9981 type = ec.CurrentType.BaseType;
9984 public override object Accept (StructuralVisitor visitor)
9986 return visitor.Visit (this);
9991 /// This class exists solely to pass the Type around and to be a dummy
9992 /// that can be passed to the conversion functions (this is used by
9993 /// foreach implementation to typecast the object return value from
9994 /// get_Current into the proper type. All code has been generated and
9995 /// we only care about the side effect conversions to be performed
9997 /// This is also now used as a placeholder where a no-action expression
9998 /// is needed (the `New' class).
10000 public class EmptyExpression : Expression
10002 sealed class OutAccessExpression : EmptyExpression
10004 public OutAccessExpression (TypeSpec t)
10009 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10011 rc.Report.Error (206, right_side.Location,
10012 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10018 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10019 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10020 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10021 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10022 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10023 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10024 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10025 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10027 public EmptyExpression (TypeSpec t)
10030 eclass = ExprClass.Value;
10031 loc = Location.Null;
10034 protected override void CloneTo (CloneContext clonectx, Expression target)
10038 public override bool ContainsEmitWithAwait ()
10043 public override Expression CreateExpressionTree (ResolveContext ec)
10045 throw new NotSupportedException ("ET");
10048 protected override Expression DoResolve (ResolveContext ec)
10053 public override void Emit (EmitContext ec)
10055 // nothing, as we only exist to not do anything.
10058 public override void EmitSideEffect (EmitContext ec)
10062 public override object Accept (StructuralVisitor visitor)
10064 return visitor.Visit (this);
10068 sealed class EmptyAwaitExpression : EmptyExpression
10070 public EmptyAwaitExpression (TypeSpec type)
10075 public override bool ContainsEmitWithAwait ()
10082 // Empty statement expression
10084 public sealed class EmptyExpressionStatement : ExpressionStatement
10086 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10088 private EmptyExpressionStatement ()
10090 loc = Location.Null;
10093 public override bool ContainsEmitWithAwait ()
10098 public override Expression CreateExpressionTree (ResolveContext ec)
10103 public override void EmitStatement (EmitContext ec)
10108 protected override Expression DoResolve (ResolveContext ec)
10110 eclass = ExprClass.Value;
10111 type = ec.BuiltinTypes.Object;
10115 public override void Emit (EmitContext ec)
10120 public override object Accept (StructuralVisitor visitor)
10122 return visitor.Visit (this);
10126 public class ErrorExpression : EmptyExpression
10128 public static readonly ErrorExpression Instance = new ErrorExpression ();
10130 private ErrorExpression ()
10131 : base (InternalType.ErrorType)
10135 public override Expression CreateExpressionTree (ResolveContext ec)
10140 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10145 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10149 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10153 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10157 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10161 public override object Accept (StructuralVisitor visitor)
10163 return visitor.Visit (this);
10167 public class UserCast : Expression {
10171 public UserCast (MethodSpec method, Expression source, Location l)
10173 if (source == null)
10174 throw new ArgumentNullException ("source");
10176 this.method = method;
10177 this.source = source;
10178 type = method.ReturnType;
10182 public Expression Source {
10188 public override bool ContainsEmitWithAwait ()
10190 return source.ContainsEmitWithAwait ();
10193 public override Expression CreateExpressionTree (ResolveContext ec)
10195 Arguments args = new Arguments (3);
10196 args.Add (new Argument (source.CreateExpressionTree (ec)));
10197 args.Add (new Argument (new TypeOf (type, loc)));
10198 args.Add (new Argument (new TypeOfMethod (method, loc)));
10199 return CreateExpressionFactoryCall (ec, "Convert", args);
10202 protected override Expression DoResolve (ResolveContext ec)
10204 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10206 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10208 eclass = ExprClass.Value;
10212 public override void Emit (EmitContext ec)
10215 ec.MarkCallEntry (loc);
10216 ec.Emit (OpCodes.Call, method);
10219 public override void FlowAnalysis (FlowAnalysisContext fc)
10221 source.FlowAnalysis (fc);
10224 public override string GetSignatureForError ()
10226 return TypeManager.CSharpSignature (method);
10229 public override SLE.Expression MakeExpression (BuilderContext ctx)
10232 return base.MakeExpression (ctx);
10234 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10240 // Holds additional type specifiers like ?, *, []
10242 public class ComposedTypeSpecifier
10244 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10246 public readonly int Dimension;
10247 public readonly Location Location;
10249 public ComposedTypeSpecifier (int specifier, Location loc)
10251 this.Dimension = specifier;
10252 this.Location = loc;
10256 public bool IsNullable {
10258 return Dimension == -1;
10262 public bool IsPointer {
10264 return Dimension == -2;
10268 public ComposedTypeSpecifier Next { get; set; }
10272 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10274 return new ComposedTypeSpecifier (dimension, loc);
10277 public static ComposedTypeSpecifier CreateNullable (Location loc)
10279 return new ComposedTypeSpecifier (-1, loc);
10282 public static ComposedTypeSpecifier CreatePointer (Location loc)
10284 return new ComposedTypeSpecifier (-2, loc);
10287 public string GetSignatureForError ()
10292 ArrayContainer.GetPostfixSignature (Dimension);
10294 return Next != null ? s + Next.GetSignatureForError () : s;
10299 // This class is used to "construct" the type during a typecast
10300 // operation. Since the Type.GetType class in .NET can parse
10301 // the type specification, we just use this to construct the type
10302 // one bit at a time.
10304 public class ComposedCast : TypeExpr {
10305 FullNamedExpression left;
10306 ComposedTypeSpecifier spec;
10308 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10311 throw new ArgumentNullException ("spec");
10315 this.loc = left.Location;
10318 public override TypeSpec ResolveAsType (IMemberContext ec)
10320 type = left.ResolveAsType (ec);
10324 eclass = ExprClass.Type;
10326 var single_spec = spec;
10328 if (single_spec.IsNullable) {
10329 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10333 single_spec = single_spec.Next;
10334 } else if (single_spec.IsPointer) {
10335 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10338 if (!ec.IsUnsafe) {
10339 UnsafeError (ec.Module.Compiler.Report, loc);
10343 type = PointerContainer.MakeType (ec.Module, type);
10344 single_spec = single_spec.Next;
10345 } while (single_spec != null && single_spec.IsPointer);
10348 if (single_spec != null && single_spec.Dimension > 0) {
10349 if (type.IsSpecialRuntimeType) {
10350 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10351 } else if (type.IsStatic) {
10352 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10353 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10354 type.GetSignatureForError ());
10356 MakeArray (ec.Module, single_spec);
10363 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10365 if (spec.Next != null)
10366 MakeArray (module, spec.Next);
10368 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10371 public override string GetSignatureForError ()
10373 return left.GetSignatureForError () + spec.GetSignatureForError ();
10376 public override object Accept (StructuralVisitor visitor)
10378 return visitor.Visit (this);
10382 class FixedBufferPtr : Expression
10384 readonly Expression array;
10386 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10388 this.type = array_type;
10389 this.array = array;
10393 public override bool ContainsEmitWithAwait ()
10395 throw new NotImplementedException ();
10398 public override Expression CreateExpressionTree (ResolveContext ec)
10400 Error_PointerInsideExpressionTree (ec);
10404 public override void Emit(EmitContext ec)
10409 protected override Expression DoResolve (ResolveContext ec)
10411 type = PointerContainer.MakeType (ec.Module, type);
10412 eclass = ExprClass.Value;
10419 // This class is used to represent the address of an array, used
10420 // only by the Fixed statement, this generates "&a [0]" construct
10421 // for fixed (char *pa = a)
10423 class ArrayPtr : FixedBufferPtr
10425 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10426 base (array, array_type, l)
10430 public override void Emit (EmitContext ec)
10435 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10440 // Encapsulates a conversion rules required for array indexes
10442 public class ArrayIndexCast : TypeCast
10444 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10445 : base (expr, returnType)
10447 if (expr.Type == returnType) // int -> int
10448 throw new ArgumentException ("unnecessary array index conversion");
10451 public override Expression CreateExpressionTree (ResolveContext ec)
10453 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10454 return base.CreateExpressionTree (ec);
10458 public override void Emit (EmitContext ec)
10462 switch (child.Type.BuiltinType) {
10463 case BuiltinTypeSpec.Type.UInt:
10464 ec.Emit (OpCodes.Conv_U);
10466 case BuiltinTypeSpec.Type.Long:
10467 ec.Emit (OpCodes.Conv_Ovf_I);
10469 case BuiltinTypeSpec.Type.ULong:
10470 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10473 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10479 // Implements the `stackalloc' keyword
10481 public class StackAlloc : Expression {
10486 public StackAlloc (Expression type, Expression count, Location l)
10489 this.count = count;
10493 public Expression TypeExpression {
10499 public Expression CountExpression {
10505 public override bool ContainsEmitWithAwait ()
10510 public override Expression CreateExpressionTree (ResolveContext ec)
10512 throw new NotSupportedException ("ET");
10515 protected override Expression DoResolve (ResolveContext ec)
10517 count = count.Resolve (ec);
10521 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10522 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10527 Constant c = count as Constant;
10528 if (c != null && c.IsNegative) {
10529 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10532 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10533 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10536 otype = t.ResolveAsType (ec);
10540 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10543 type = PointerContainer.MakeType (ec.Module, otype);
10544 eclass = ExprClass.Value;
10549 public override void Emit (EmitContext ec)
10551 int size = BuiltinTypeSpec.GetSize (otype);
10556 ec.Emit (OpCodes.Sizeof, otype);
10560 ec.Emit (OpCodes.Mul_Ovf_Un);
10561 ec.Emit (OpCodes.Localloc);
10564 protected override void CloneTo (CloneContext clonectx, Expression t)
10566 StackAlloc target = (StackAlloc) t;
10567 target.count = count.Clone (clonectx);
10568 target.t = t.Clone (clonectx);
10571 public override object Accept (StructuralVisitor visitor)
10573 return visitor.Visit (this);
10578 // An object initializer expression
10580 public class ElementInitializer : Assign
10582 public readonly string Name;
10584 public ElementInitializer (string name, Expression initializer, Location loc)
10585 : base (null, initializer, loc)
10590 protected override void CloneTo (CloneContext clonectx, Expression t)
10592 ElementInitializer target = (ElementInitializer) t;
10593 target.source = source.Clone (clonectx);
10596 public override Expression CreateExpressionTree (ResolveContext ec)
10598 Arguments args = new Arguments (2);
10599 FieldExpr fe = target as FieldExpr;
10601 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10603 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10606 Expression arg_expr;
10607 var cinit = source as CollectionOrObjectInitializers;
10608 if (cinit == null) {
10610 arg_expr = source.CreateExpressionTree (ec);
10612 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10613 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10616 args.Add (new Argument (arg_expr));
10617 return CreateExpressionFactoryCall (ec, mname, args);
10620 protected override Expression DoResolve (ResolveContext ec)
10622 if (source == null)
10623 return EmptyExpressionStatement.Instance;
10625 var t = ec.CurrentInitializerVariable.Type;
10626 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10627 Arguments args = new Arguments (1);
10628 args.Add (new Argument (ec.CurrentInitializerVariable));
10629 target = new DynamicMemberBinder (Name, args, loc);
10632 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10633 if (member == null) {
10634 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10636 if (member != null) {
10637 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10638 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10643 if (member == null) {
10644 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10648 if (!(member is PropertyExpr || member is FieldExpr)) {
10649 ec.Report.Error (1913, loc,
10650 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10651 member.GetSignatureForError ());
10656 var me = member as MemberExpr;
10658 ec.Report.Error (1914, loc,
10659 "Static field or property `{0}' cannot be assigned in an object initializer",
10660 me.GetSignatureForError ());
10664 me.InstanceExpression = ec.CurrentInitializerVariable;
10667 if (source is CollectionOrObjectInitializers) {
10668 Expression previous = ec.CurrentInitializerVariable;
10669 ec.CurrentInitializerVariable = target;
10670 source = source.Resolve (ec);
10671 ec.CurrentInitializerVariable = previous;
10672 if (source == null)
10675 eclass = source.eclass;
10676 type = source.Type;
10680 return base.DoResolve (ec);
10683 public override void EmitStatement (EmitContext ec)
10685 if (source is CollectionOrObjectInitializers)
10688 base.EmitStatement (ec);
10693 // A collection initializer expression
10695 class CollectionElementInitializer : Invocation
10697 public class ElementInitializerArgument : Argument
10699 public ElementInitializerArgument (Expression e)
10705 sealed class AddMemberAccess : MemberAccess
10707 public AddMemberAccess (Expression expr, Location loc)
10708 : base (expr, "Add", loc)
10712 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10714 if (TypeManager.HasElementType (type))
10717 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10721 public CollectionElementInitializer (Expression argument)
10722 : base (null, new Arguments (1))
10724 base.arguments.Add (new ElementInitializerArgument (argument));
10725 this.loc = argument.Location;
10728 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10729 : base (null, new Arguments (arguments.Count))
10731 foreach (Expression e in arguments)
10732 base.arguments.Add (new ElementInitializerArgument (e));
10737 public CollectionElementInitializer (Location loc)
10738 : base (null, null)
10743 public override Expression CreateExpressionTree (ResolveContext ec)
10745 Arguments args = new Arguments (2);
10746 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10748 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10749 foreach (Argument a in arguments)
10750 expr_initializers.Add (a.CreateExpressionTree (ec));
10752 args.Add (new Argument (new ArrayCreation (
10753 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10754 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10757 protected override void CloneTo (CloneContext clonectx, Expression t)
10759 CollectionElementInitializer target = (CollectionElementInitializer) t;
10760 if (arguments != null)
10761 target.arguments = arguments.Clone (clonectx);
10764 protected override Expression DoResolve (ResolveContext ec)
10766 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10768 return base.DoResolve (ec);
10773 // A block of object or collection initializers
10775 public class CollectionOrObjectInitializers : ExpressionStatement
10777 IList<Expression> initializers;
10778 bool is_collection_initialization;
10780 public CollectionOrObjectInitializers (Location loc)
10781 : this (new Expression[0], loc)
10785 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10787 this.initializers = initializers;
10791 public IList<Expression> Initializers {
10793 return initializers;
10797 public bool IsEmpty {
10799 return initializers.Count == 0;
10803 public bool IsCollectionInitializer {
10805 return is_collection_initialization;
10809 protected override void CloneTo (CloneContext clonectx, Expression target)
10811 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10813 t.initializers = new List<Expression> (initializers.Count);
10814 foreach (var e in initializers)
10815 t.initializers.Add (e.Clone (clonectx));
10818 public override bool ContainsEmitWithAwait ()
10820 foreach (var e in initializers) {
10821 if (e.ContainsEmitWithAwait ())
10828 public override Expression CreateExpressionTree (ResolveContext ec)
10830 return CreateExpressionTree (ec, false);
10833 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10835 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10836 foreach (Expression e in initializers) {
10837 Expression expr = e.CreateExpressionTree (ec);
10839 expr_initializers.Add (expr);
10843 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10845 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10848 protected override Expression DoResolve (ResolveContext ec)
10850 List<string> element_names = null;
10851 for (int i = 0; i < initializers.Count; ++i) {
10852 Expression initializer = initializers [i];
10853 ElementInitializer element_initializer = initializer as ElementInitializer;
10856 if (element_initializer != null) {
10857 element_names = new List<string> (initializers.Count);
10858 element_names.Add (element_initializer.Name);
10859 } else if (initializer is CompletingExpression){
10860 initializer.Resolve (ec);
10861 throw new InternalErrorException ("This line should never be reached");
10863 var t = ec.CurrentInitializerVariable.Type;
10864 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10865 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10866 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10867 "object initializer because type `{1}' does not implement `{2}' interface",
10868 ec.CurrentInitializerVariable.GetSignatureForError (),
10869 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10870 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10873 is_collection_initialization = true;
10876 if (is_collection_initialization != (element_initializer == null)) {
10877 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10878 is_collection_initialization ? "collection initializer" : "object initializer");
10882 if (!is_collection_initialization) {
10883 if (element_names.Contains (element_initializer.Name)) {
10884 ec.Report.Error (1912, element_initializer.Location,
10885 "An object initializer includes more than one member `{0}' initialization",
10886 element_initializer.Name);
10888 element_names.Add (element_initializer.Name);
10893 Expression e = initializer.Resolve (ec);
10894 if (e == EmptyExpressionStatement.Instance)
10895 initializers.RemoveAt (i--);
10897 initializers [i] = e;
10900 type = ec.CurrentInitializerVariable.Type;
10901 if (is_collection_initialization) {
10902 if (TypeManager.HasElementType (type)) {
10903 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10904 type.GetSignatureForError ());
10908 eclass = ExprClass.Variable;
10912 public override void Emit (EmitContext ec)
10914 EmitStatement (ec);
10917 public override void EmitStatement (EmitContext ec)
10919 foreach (ExpressionStatement e in initializers) {
10920 // TODO: need location region
10921 ec.Mark (e.Location);
10922 e.EmitStatement (ec);
10926 public override void FlowAnalysis (FlowAnalysisContext fc)
10928 foreach (var initializer in initializers)
10929 initializer.FlowAnalysis (fc);
10934 // New expression with element/object initializers
10936 public class NewInitialize : New
10939 // This class serves as a proxy for variable initializer target instances.
10940 // A real variable is assigned later when we resolve left side of an
10943 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10945 NewInitialize new_instance;
10947 public InitializerTargetExpression (NewInitialize newInstance)
10949 this.type = newInstance.type;
10950 this.loc = newInstance.loc;
10951 this.eclass = newInstance.eclass;
10952 this.new_instance = newInstance;
10955 public override bool ContainsEmitWithAwait ()
10960 public override Expression CreateExpressionTree (ResolveContext ec)
10962 // Should not be reached
10963 throw new NotSupportedException ("ET");
10966 protected override Expression DoResolve (ResolveContext ec)
10971 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10976 public override void Emit (EmitContext ec)
10978 Expression e = (Expression) new_instance.instance;
10982 public override Expression EmitToField (EmitContext ec)
10984 return (Expression) new_instance.instance;
10987 #region IMemoryLocation Members
10989 public void AddressOf (EmitContext ec, AddressOp mode)
10991 new_instance.instance.AddressOf (ec, mode);
10997 CollectionOrObjectInitializers initializers;
10998 IMemoryLocation instance;
10999 DynamicExpressionStatement dynamic;
11001 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
11002 : base (requested_type, arguments, l)
11004 this.initializers = initializers;
11007 public CollectionOrObjectInitializers Initializers {
11009 return initializers;
11013 protected override void CloneTo (CloneContext clonectx, Expression t)
11015 base.CloneTo (clonectx, t);
11017 NewInitialize target = (NewInitialize) t;
11018 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
11021 public override bool ContainsEmitWithAwait ()
11023 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
11026 public override Expression CreateExpressionTree (ResolveContext ec)
11028 Arguments args = new Arguments (2);
11029 args.Add (new Argument (base.CreateExpressionTree (ec)));
11030 if (!initializers.IsEmpty)
11031 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
11033 return CreateExpressionFactoryCall (ec,
11034 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
11038 protected override Expression DoResolve (ResolveContext ec)
11040 Expression e = base.DoResolve (ec);
11044 if (type.IsDelegate) {
11045 ec.Report.Error (1958, Initializers.Location,
11046 "Object and collection initializers cannot be used to instantiate a delegate");
11049 Expression previous = ec.CurrentInitializerVariable;
11050 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
11051 initializers.Resolve (ec);
11052 ec.CurrentInitializerVariable = previous;
11054 dynamic = e as DynamicExpressionStatement;
11055 if (dynamic != null)
11061 public override bool Emit (EmitContext ec, IMemoryLocation target)
11063 bool left_on_stack;
11064 if (dynamic != null) {
11066 left_on_stack = true;
11068 left_on_stack = base.Emit (ec, target);
11071 if (initializers.IsEmpty)
11072 return left_on_stack;
11074 LocalTemporary temp = null;
11076 instance = target as LocalTemporary;
11078 if (instance == null) {
11079 if (!left_on_stack) {
11080 VariableReference vr = target as VariableReference;
11082 // FIXME: This still does not work correctly for pre-set variables
11083 if (vr != null && vr.IsRef)
11084 target.AddressOf (ec, AddressOp.Load);
11086 ((Expression) target).Emit (ec);
11087 left_on_stack = true;
11090 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11091 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
11093 temp = new LocalTemporary (type);
11098 if (left_on_stack && temp != null)
11101 initializers.Emit (ec);
11103 if (left_on_stack) {
11104 if (temp != null) {
11108 ((Expression) instance).Emit (ec);
11112 return left_on_stack;
11115 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
11117 instance = base.EmitAddressOf (ec, Mode);
11119 if (!initializers.IsEmpty)
11120 initializers.Emit (ec);
11125 public override void FlowAnalysis (FlowAnalysisContext fc)
11127 base.FlowAnalysis (fc);
11128 initializers.FlowAnalysis (fc);
11131 public override object Accept (StructuralVisitor visitor)
11133 return visitor.Visit (this);
11137 public class NewAnonymousType : New
11139 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
11141 List<AnonymousTypeParameter> parameters;
11142 readonly TypeContainer parent;
11143 AnonymousTypeClass anonymous_type;
11145 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11146 : base (null, null, loc)
11148 this.parameters = parameters;
11149 this.parent = parent;
11152 public List<AnonymousTypeParameter> Parameters {
11154 return this.parameters;
11158 protected override void CloneTo (CloneContext clonectx, Expression target)
11160 if (parameters == null)
11163 NewAnonymousType t = (NewAnonymousType) target;
11164 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11165 foreach (AnonymousTypeParameter atp in parameters)
11166 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11169 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11171 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11175 type = AnonymousTypeClass.Create (parent, parameters, loc);
11179 int errors = ec.Report.Errors;
11180 type.CreateContainer ();
11181 type.DefineContainer ();
11183 if ((ec.Report.Errors - errors) == 0) {
11184 parent.Module.AddAnonymousType (type);
11185 type.PrepareEmit ();
11191 public override Expression CreateExpressionTree (ResolveContext ec)
11193 if (parameters == null)
11194 return base.CreateExpressionTree (ec);
11196 var init = new ArrayInitializer (parameters.Count, loc);
11197 foreach (var m in anonymous_type.Members) {
11198 var p = m as Property;
11200 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11203 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11204 foreach (Argument a in arguments)
11205 ctor_args.Add (a.CreateExpressionTree (ec));
11207 Arguments args = new Arguments (3);
11208 args.Add (new Argument (new TypeOfMethod (method, loc)));
11209 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11210 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11212 return CreateExpressionFactoryCall (ec, "New", args);
11215 protected override Expression DoResolve (ResolveContext ec)
11217 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11218 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11222 if (parameters == null) {
11223 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11224 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11225 return base.DoResolve (ec);
11228 bool error = false;
11229 arguments = new Arguments (parameters.Count);
11230 var t_args = new TypeSpec [parameters.Count];
11231 for (int i = 0; i < parameters.Count; ++i) {
11232 Expression e = parameters [i].Resolve (ec);
11238 arguments.Add (new Argument (e));
11239 t_args [i] = e.Type;
11245 anonymous_type = CreateAnonymousType (ec, parameters);
11246 if (anonymous_type == null)
11249 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11250 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11251 eclass = ExprClass.Value;
11255 public override object Accept (StructuralVisitor visitor)
11257 return visitor.Visit (this);
11261 public class AnonymousTypeParameter : ShimExpression
11263 public readonly string Name;
11265 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11266 : base (initializer)
11272 public AnonymousTypeParameter (Parameter parameter)
11273 : base (new SimpleName (parameter.Name, parameter.Location))
11275 this.Name = parameter.Name;
11276 this.loc = parameter.Location;
11279 public override bool Equals (object o)
11281 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11282 return other != null && Name == other.Name;
11285 public override int GetHashCode ()
11287 return Name.GetHashCode ();
11290 protected override Expression DoResolve (ResolveContext ec)
11292 Expression e = expr.Resolve (ec);
11296 if (e.eclass == ExprClass.MethodGroup) {
11297 Error_InvalidInitializer (ec, e.ExprClassName);
11302 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11303 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11310 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11312 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11313 Name, initializer);
11317 public class CatchFilterExpression : BooleanExpression
11319 public CatchFilterExpression (Expression expr, Location loc)