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 left.FlowAnalysis (fc);
2614 right.FlowAnalysis (fc);
2619 // Optimized version when on-true/on-false data are not needed
2621 bool set_on_true_false;
2622 if (fc.DefiniteAssignmentOnTrue == null && fc.DefiniteAssignmentOnFalse == null) {
2623 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
2624 set_on_true_false = false;
2626 set_on_true_false = true;
2629 left.FlowAnalysis (fc);
2630 var left_fc = fc.DefiniteAssignment;
2631 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
2632 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
2634 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
2635 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
2636 right.FlowAnalysis (fc);
2637 fc.DefiniteAssignment = left_fc;
2639 if (!set_on_true_false) {
2640 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = null;
2644 if (oper == Operator.LogicalOr) {
2645 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue);
2646 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
2648 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
2649 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet (left_fc_onfalse);
2654 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2656 string GetOperatorExpressionTypeName ()
2659 case Operator.Addition:
2660 return IsCompound ? "AddAssign" : "Add";
2661 case Operator.BitwiseAnd:
2662 return IsCompound ? "AndAssign" : "And";
2663 case Operator.BitwiseOr:
2664 return IsCompound ? "OrAssign" : "Or";
2665 case Operator.Division:
2666 return IsCompound ? "DivideAssign" : "Divide";
2667 case Operator.ExclusiveOr:
2668 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2669 case Operator.Equality:
2671 case Operator.GreaterThan:
2672 return "GreaterThan";
2673 case Operator.GreaterThanOrEqual:
2674 return "GreaterThanOrEqual";
2675 case Operator.Inequality:
2677 case Operator.LeftShift:
2678 return IsCompound ? "LeftShiftAssign" : "LeftShift";
2679 case Operator.LessThan:
2681 case Operator.LessThanOrEqual:
2682 return "LessThanOrEqual";
2683 case Operator.LogicalAnd:
2685 case Operator.LogicalOr:
2687 case Operator.Modulus:
2688 return IsCompound ? "ModuloAssign" : "Modulo";
2689 case Operator.Multiply:
2690 return IsCompound ? "MultiplyAssign" : "Multiply";
2691 case Operator.RightShift:
2692 return IsCompound ? "RightShiftAssign" : "RightShift";
2693 case Operator.Subtraction:
2694 return IsCompound ? "SubtractAssign" : "Subtract";
2696 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2700 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2703 case Operator.Addition:
2704 return CSharp.Operator.OpType.Addition;
2705 case Operator.BitwiseAnd:
2706 case Operator.LogicalAnd:
2707 return CSharp.Operator.OpType.BitwiseAnd;
2708 case Operator.BitwiseOr:
2709 case Operator.LogicalOr:
2710 return CSharp.Operator.OpType.BitwiseOr;
2711 case Operator.Division:
2712 return CSharp.Operator.OpType.Division;
2713 case Operator.Equality:
2714 return CSharp.Operator.OpType.Equality;
2715 case Operator.ExclusiveOr:
2716 return CSharp.Operator.OpType.ExclusiveOr;
2717 case Operator.GreaterThan:
2718 return CSharp.Operator.OpType.GreaterThan;
2719 case Operator.GreaterThanOrEqual:
2720 return CSharp.Operator.OpType.GreaterThanOrEqual;
2721 case Operator.Inequality:
2722 return CSharp.Operator.OpType.Inequality;
2723 case Operator.LeftShift:
2724 return CSharp.Operator.OpType.LeftShift;
2725 case Operator.LessThan:
2726 return CSharp.Operator.OpType.LessThan;
2727 case Operator.LessThanOrEqual:
2728 return CSharp.Operator.OpType.LessThanOrEqual;
2729 case Operator.Modulus:
2730 return CSharp.Operator.OpType.Modulus;
2731 case Operator.Multiply:
2732 return CSharp.Operator.OpType.Multiply;
2733 case Operator.RightShift:
2734 return CSharp.Operator.OpType.RightShift;
2735 case Operator.Subtraction:
2736 return CSharp.Operator.OpType.Subtraction;
2738 throw new InternalErrorException (op.ToString ());
2742 public override bool ContainsEmitWithAwait ()
2744 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
2747 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
2752 case Operator.Multiply:
2753 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2754 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2755 opcode = OpCodes.Mul_Ovf;
2756 else if (!IsFloat (l))
2757 opcode = OpCodes.Mul_Ovf_Un;
2759 opcode = OpCodes.Mul;
2761 opcode = OpCodes.Mul;
2765 case Operator.Division:
2767 opcode = OpCodes.Div_Un;
2769 opcode = OpCodes.Div;
2772 case Operator.Modulus:
2774 opcode = OpCodes.Rem_Un;
2776 opcode = OpCodes.Rem;
2779 case Operator.Addition:
2780 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2781 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2782 opcode = OpCodes.Add_Ovf;
2783 else if (!IsFloat (l))
2784 opcode = OpCodes.Add_Ovf_Un;
2786 opcode = OpCodes.Add;
2788 opcode = OpCodes.Add;
2791 case Operator.Subtraction:
2792 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2793 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2794 opcode = OpCodes.Sub_Ovf;
2795 else if (!IsFloat (l))
2796 opcode = OpCodes.Sub_Ovf_Un;
2798 opcode = OpCodes.Sub;
2800 opcode = OpCodes.Sub;
2803 case Operator.RightShift:
2804 if (!(right is IntConstant)) {
2805 ec.EmitInt (GetShiftMask (l));
2806 ec.Emit (OpCodes.And);
2810 opcode = OpCodes.Shr_Un;
2812 opcode = OpCodes.Shr;
2815 case Operator.LeftShift:
2816 if (!(right is IntConstant)) {
2817 ec.EmitInt (GetShiftMask (l));
2818 ec.Emit (OpCodes.And);
2821 opcode = OpCodes.Shl;
2824 case Operator.Equality:
2825 opcode = OpCodes.Ceq;
2828 case Operator.Inequality:
2829 ec.Emit (OpCodes.Ceq);
2832 opcode = OpCodes.Ceq;
2835 case Operator.LessThan:
2837 opcode = OpCodes.Clt_Un;
2839 opcode = OpCodes.Clt;
2842 case Operator.GreaterThan:
2844 opcode = OpCodes.Cgt_Un;
2846 opcode = OpCodes.Cgt;
2849 case Operator.LessThanOrEqual:
2850 if (IsUnsigned (l) || IsFloat (l))
2851 ec.Emit (OpCodes.Cgt_Un);
2853 ec.Emit (OpCodes.Cgt);
2856 opcode = OpCodes.Ceq;
2859 case Operator.GreaterThanOrEqual:
2860 if (IsUnsigned (l) || IsFloat (l))
2861 ec.Emit (OpCodes.Clt_Un);
2863 ec.Emit (OpCodes.Clt);
2867 opcode = OpCodes.Ceq;
2870 case Operator.BitwiseOr:
2871 opcode = OpCodes.Or;
2874 case Operator.BitwiseAnd:
2875 opcode = OpCodes.And;
2878 case Operator.ExclusiveOr:
2879 opcode = OpCodes.Xor;
2883 throw new InternalErrorException (oper.ToString ());
2889 static int GetShiftMask (TypeSpec type)
2891 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
2894 static bool IsUnsigned (TypeSpec t)
2896 switch (t.BuiltinType) {
2897 case BuiltinTypeSpec.Type.Char:
2898 case BuiltinTypeSpec.Type.UInt:
2899 case BuiltinTypeSpec.Type.ULong:
2900 case BuiltinTypeSpec.Type.UShort:
2901 case BuiltinTypeSpec.Type.Byte:
2908 static bool IsFloat (TypeSpec t)
2910 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2913 public Expression ResolveOperator (ResolveContext rc)
2915 eclass = ExprClass.Value;
2917 TypeSpec l = left.Type;
2918 TypeSpec r = right.Type;
2920 bool primitives_only = false;
2923 // Handles predefined primitive types
2925 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
2926 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
2927 if ((oper & Operator.ShiftMask) == 0) {
2928 if (!DoBinaryOperatorPromotion (rc))
2931 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
2935 if (l.IsPointer || r.IsPointer)
2936 return ResolveOperatorPointer (rc, l, r);
2939 expr = ResolveUserOperator (rc, left, right);
2944 bool lenum = l.IsEnum;
2945 bool renum = r.IsEnum;
2946 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2950 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2951 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
2956 if ((oper & Operator.BitwiseMask) != 0) {
2957 expr = EmptyCast.Create (expr, type);
2958 AddEnumResultCast (type);
2960 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
2961 expr = OptimizeAndOperation (expr);
2965 left = ConvertEnumOperandToUnderlyingType (rc, left);
2966 right = ConvertEnumOperandToUnderlyingType (rc, right);
2969 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
2970 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
2974 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
2977 // We cannot break here there is also Enum + String possible match
2978 // which is not ambiguous with predefined enum operators
2981 left = ConvertEnumOperandToUnderlyingType (rc, left);
2982 right = ConvertEnumOperandToUnderlyingType (rc, right);
2986 } else if (l.IsDelegate || r.IsDelegate) {
2990 expr = ResolveOperatorDelegate (rc, l, r);
2992 // TODO: Can this be ambiguous
3000 // Equality operators are more complicated
3002 if ((oper & Operator.EqualityMask) != 0) {
3003 return ResolveEquality (rc, l, r, primitives_only);
3006 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3010 if (primitives_only)
3014 // Lifted operators have lower priority
3016 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3019 static bool IsEnumOrNullableEnum (TypeSpec type)
3021 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3025 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3026 // if 'left' is not an enumeration constant, create one from the type of 'right'
3027 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3030 case Operator.BitwiseOr:
3031 case Operator.BitwiseAnd:
3032 case Operator.ExclusiveOr:
3033 case Operator.Equality:
3034 case Operator.Inequality:
3035 case Operator.LessThan:
3036 case Operator.LessThanOrEqual:
3037 case Operator.GreaterThan:
3038 case Operator.GreaterThanOrEqual:
3039 if (left.Type.IsEnum)
3042 if (left.IsZeroInteger)
3043 return left.Reduce (ec, right.Type);
3047 case Operator.Addition:
3048 case Operator.Subtraction:
3051 case Operator.Multiply:
3052 case Operator.Division:
3053 case Operator.Modulus:
3054 case Operator.LeftShift:
3055 case Operator.RightShift:
3056 if (right.Type.IsEnum || left.Type.IsEnum)
3065 // The `|' operator used on types which were extended is dangerous
3067 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3069 OpcodeCast lcast = left as OpcodeCast;
3070 if (lcast != null) {
3071 if (IsUnsigned (lcast.UnderlyingType))
3075 OpcodeCast rcast = right as OpcodeCast;
3076 if (rcast != null) {
3077 if (IsUnsigned (rcast.UnderlyingType))
3081 if (lcast == null && rcast == null)
3084 // FIXME: consider constants
3086 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3087 ec.Report.Warning (675, 3, loc,
3088 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3089 ltype.GetSignatureForError ());
3092 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3094 return new PredefinedOperator[] {
3096 // Pointer arithmetic:
3098 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3099 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3100 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3101 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3103 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3104 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3105 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3106 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3109 // T* operator + (int y, T* x);
3110 // T* operator + (uint y, T *x);
3111 // T* operator + (long y, T *x);
3112 // T* operator + (ulong y, T *x);
3114 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3115 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3116 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3117 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3120 // long operator - (T* x, T *y)
3122 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3126 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3128 TypeSpec bool_type = types.Bool;
3131 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3132 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3133 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3134 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3135 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3136 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3137 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3139 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3140 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3141 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3142 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3143 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3144 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3145 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3147 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3148 // Remaining string operators are in lifted tables
3150 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3152 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3153 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3154 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3158 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3160 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3161 if (nullable == null)
3162 return new PredefinedOperator [0];
3164 var types = module.Compiler.BuiltinTypes;
3165 var bool_type = types.Bool;
3167 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3168 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3169 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3170 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3171 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3172 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3173 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3174 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3177 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3178 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3179 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3180 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3181 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3182 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3183 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3185 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3186 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3187 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3188 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3189 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3190 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3191 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3193 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3195 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3196 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3197 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3200 // Not strictly lifted but need to be in second group otherwise expressions like
3201 // int + null would resolve to +(object, string) instead of +(int?, int?)
3203 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3204 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3209 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3211 TypeSpec bool_type = types.Bool;
3214 new PredefinedEqualityOperator (types.String, bool_type),
3215 new PredefinedEqualityOperator (types.Delegate, bool_type),
3216 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3217 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3218 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3219 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3220 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3221 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3222 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3223 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3227 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3229 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3231 if (nullable == null)
3232 return new PredefinedOperator [0];
3234 var types = module.Compiler.BuiltinTypes;
3235 var bool_type = types.Bool;
3236 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3237 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3238 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3239 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3240 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3241 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3242 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3243 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3246 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3247 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3248 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3249 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3250 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3251 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3252 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3253 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3258 // 7.2.6.2 Binary numeric promotions
3260 bool DoBinaryOperatorPromotion (ResolveContext rc)
3262 TypeSpec ltype = left.Type;
3263 if (ltype.IsNullableType) {
3264 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
3268 // This is numeric promotion code only
3270 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
3273 TypeSpec rtype = right.Type;
3274 if (rtype.IsNullableType) {
3275 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
3278 var lb = ltype.BuiltinType;
3279 var rb = rtype.BuiltinType;
3283 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
3284 type = rc.BuiltinTypes.Decimal;
3285 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
3286 type = rc.BuiltinTypes.Double;
3287 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
3288 type = rc.BuiltinTypes.Float;
3289 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
3290 type = rc.BuiltinTypes.ULong;
3292 if (IsSignedType (lb)) {
3293 expr = ConvertSignedConstant (left, type);
3297 } else if (IsSignedType (rb)) {
3298 expr = ConvertSignedConstant (right, type);
3304 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
3305 type = rc.BuiltinTypes.Long;
3306 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
3307 type = rc.BuiltinTypes.UInt;
3309 if (IsSignedType (lb)) {
3310 expr = ConvertSignedConstant (left, type);
3312 type = rc.BuiltinTypes.Long;
3313 } else if (IsSignedType (rb)) {
3314 expr = ConvertSignedConstant (right, type);
3316 type = rc.BuiltinTypes.Long;
3319 type = rc.BuiltinTypes.Int;
3322 if (ltype != type) {
3323 expr = PromoteExpression (rc, left, type);
3330 if (rtype != type) {
3331 expr = PromoteExpression (rc, right, type);
3341 static bool IsSignedType (BuiltinTypeSpec.Type type)
3344 case BuiltinTypeSpec.Type.Int:
3345 case BuiltinTypeSpec.Type.Short:
3346 case BuiltinTypeSpec.Type.SByte:
3347 case BuiltinTypeSpec.Type.Long:
3354 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
3356 var c = expr as Constant;
3360 return c.ConvertImplicitly (type);
3363 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
3365 if (expr.Type.IsNullableType) {
3366 return Convert.ImplicitConversionStandard (rc, expr,
3367 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
3370 var c = expr as Constant;
3372 return c.ConvertImplicitly (type);
3374 return Convert.ImplicitNumericConversion (expr, type);
3377 protected override Expression DoResolve (ResolveContext ec)
3382 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
3383 left = ((ParenthesizedExpression) left).Expr;
3384 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
3388 if (left.eclass == ExprClass.Type) {
3389 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
3393 left = left.Resolve (ec);
3398 right = right.Resolve (ec);
3402 Constant lc = left as Constant;
3403 Constant rc = right as Constant;
3405 // The conversion rules are ignored in enum context but why
3406 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
3407 lc = EnumLiftUp (ec, lc, rc);
3409 rc = EnumLiftUp (ec, rc, lc);
3412 if (rc != null && lc != null) {
3413 int prev_e = ec.Report.Errors;
3414 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
3415 if (e != null || ec.Report.Errors != prev_e)
3419 // Comparison warnings
3420 if ((oper & Operator.ComparisonMask) != 0) {
3421 if (left.Equals (right)) {
3422 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
3424 CheckOutOfRangeComparison (ec, lc, right.Type);
3425 CheckOutOfRangeComparison (ec, rc, left.Type);
3428 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3429 return DoResolveDynamic (ec);
3431 return DoResolveCore (ec, left, right);
3434 Expression DoResolveDynamic (ResolveContext rc)
3437 var rt = right.Type;
3438 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
3439 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
3440 Error_OperatorCannotBeApplied (rc, left, right);
3447 // Special handling for logical boolean operators which require rhs not to be
3448 // evaluated based on lhs value
3450 if ((oper & Operator.LogicalMask) != 0) {
3451 Expression cond_left, cond_right, expr;
3453 args = new Arguments (2);
3455 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3456 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
3458 var cond_args = new Arguments (1);
3459 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
3462 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
3463 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
3465 left = temp.CreateReferenceExpression (rc, loc);
3466 if (oper == Operator.LogicalAnd) {
3467 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
3470 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
3474 args.Add (new Argument (left));
3475 args.Add (new Argument (right));
3476 cond_right = new DynamicExpressionStatement (this, args, loc);
3478 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
3480 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
3481 args.Add (new Argument (right));
3482 right = new DynamicExpressionStatement (this, args, loc);
3485 // bool && dynamic => (temp = left) ? temp && right : temp;
3486 // bool || dynamic => (temp = left) ? temp : temp || right;
3488 if (oper == Operator.LogicalAnd) {
3490 cond_right = temp.CreateReferenceExpression (rc, loc);
3492 cond_left = temp.CreateReferenceExpression (rc, loc);
3496 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
3499 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
3502 args = new Arguments (2);
3503 args.Add (new Argument (left));
3504 args.Add (new Argument (right));
3505 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
3508 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
3510 Expression expr = ResolveOperator (ec);
3512 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
3514 if (left == null || right == null)
3515 throw new InternalErrorException ("Invalid conversion");
3517 if (oper == Operator.BitwiseOr)
3518 CheckBitwiseOrOnSignExtended (ec);
3523 public override SLE.Expression MakeExpression (BuilderContext ctx)
3525 return MakeExpression (ctx, left, right);
3528 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
3530 var le = left.MakeExpression (ctx);
3531 var re = right.MakeExpression (ctx);
3532 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3535 case Operator.Addition:
3536 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3537 case Operator.BitwiseAnd:
3538 return SLE.Expression.And (le, re);
3539 case Operator.BitwiseOr:
3540 return SLE.Expression.Or (le, re);
3541 case Operator.Division:
3542 return SLE.Expression.Divide (le, re);
3543 case Operator.Equality:
3544 return SLE.Expression.Equal (le, re);
3545 case Operator.ExclusiveOr:
3546 return SLE.Expression.ExclusiveOr (le, re);
3547 case Operator.GreaterThan:
3548 return SLE.Expression.GreaterThan (le, re);
3549 case Operator.GreaterThanOrEqual:
3550 return SLE.Expression.GreaterThanOrEqual (le, re);
3551 case Operator.Inequality:
3552 return SLE.Expression.NotEqual (le, re);
3553 case Operator.LeftShift:
3554 return SLE.Expression.LeftShift (le, re);
3555 case Operator.LessThan:
3556 return SLE.Expression.LessThan (le, re);
3557 case Operator.LessThanOrEqual:
3558 return SLE.Expression.LessThanOrEqual (le, re);
3559 case Operator.LogicalAnd:
3560 return SLE.Expression.AndAlso (le, re);
3561 case Operator.LogicalOr:
3562 return SLE.Expression.OrElse (le, re);
3563 case Operator.Modulus:
3564 return SLE.Expression.Modulo (le, re);
3565 case Operator.Multiply:
3566 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3567 case Operator.RightShift:
3568 return SLE.Expression.RightShift (le, re);
3569 case Operator.Subtraction:
3570 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3572 throw new NotImplementedException (oper.ToString ());
3577 // D operator + (D x, D y)
3578 // D operator - (D x, D y)
3580 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3582 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3584 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3585 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3590 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3591 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3601 MethodSpec method = null;
3602 Arguments args = new Arguments (2);
3603 args.Add (new Argument (left));
3604 args.Add (new Argument (right));
3606 if (oper == Operator.Addition) {
3607 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3608 } else if (oper == Operator.Subtraction) {
3609 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3613 return new EmptyExpression (ec.BuiltinTypes.Decimal);
3615 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
3616 return new ClassCast (expr, l);
3620 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
3622 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3625 // bool operator == (E x, E y);
3626 // bool operator != (E x, E y);
3627 // bool operator < (E x, E y);
3628 // bool operator > (E x, E y);
3629 // bool operator <= (E x, E y);
3630 // bool operator >= (E x, E y);
3632 // E operator & (E x, E y);
3633 // E operator | (E x, E y);
3634 // E operator ^ (E x, E y);
3637 if ((oper & Operator.ComparisonMask) != 0) {
3638 type = rc.BuiltinTypes.Bool;
3644 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3650 if (ltype == rtype) {
3654 var lifted = new Nullable.LiftedBinaryOperator (this);
3656 lifted.Right = right;
3657 return lifted.Resolve (rc);
3660 if (renum && !ltype.IsNullableType) {
3661 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
3666 } else if (lenum && !rtype.IsNullableType) {
3667 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
3675 // Now try lifted version of predefined operator
3677 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
3678 if (nullable_type != null) {
3679 if (renum && !ltype.IsNullableType) {
3680 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
3682 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3685 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3688 if ((oper & Operator.BitwiseMask) != 0)
3692 if ((oper & Operator.BitwiseMask) != 0)
3693 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3695 return CreateLiftedValueTypeResult (rc, rtype);
3699 var lifted = new Nullable.LiftedBinaryOperator (this);
3701 lifted.Right = right;
3702 return lifted.Resolve (rc);
3704 } else if (lenum && !rtype.IsNullableType) {
3705 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
3707 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
3710 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
3713 if ((oper & Operator.BitwiseMask) != 0)
3717 if ((oper & Operator.BitwiseMask) != 0)
3718 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3720 return CreateLiftedValueTypeResult (rc, ltype);
3724 var lifted = new Nullable.LiftedBinaryOperator (this);
3726 lifted.Right = expr;
3727 return lifted.Resolve (rc);
3729 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
3731 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3732 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
3734 if ((oper & Operator.RelationalMask) != 0)
3735 return CreateLiftedValueTypeResult (rc, rtype);
3737 if ((oper & Operator.BitwiseMask) != 0)
3738 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3740 // Equality operators are valid between E? and null
3743 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
3749 var lifted = new Nullable.LiftedBinaryOperator (this);
3751 lifted.Right = right;
3752 return lifted.Resolve (rc);
3754 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
3756 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3757 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
3759 if ((oper & Operator.RelationalMask) != 0)
3760 return CreateLiftedValueTypeResult (rc, ltype);
3762 if ((oper & Operator.BitwiseMask) != 0)
3763 return Nullable.LiftedNull.CreateFromExpression (rc, this);
3765 // Equality operators are valid between E? and null
3768 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
3774 var lifted = new Nullable.LiftedBinaryOperator (this);
3776 lifted.Right = expr;
3777 return lifted.Resolve (rc);
3785 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr)
3787 TypeSpec underlying_type;
3788 if (expr.Type.IsNullableType) {
3789 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
3791 underlying_type = EnumSpec.GetUnderlyingType (nt);
3793 underlying_type = nt;
3794 } else if (expr.Type.IsEnum) {
3795 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
3797 underlying_type = expr.Type;
3800 switch (underlying_type.BuiltinType) {
3801 case BuiltinTypeSpec.Type.SByte:
3802 case BuiltinTypeSpec.Type.Byte:
3803 case BuiltinTypeSpec.Type.Short:
3804 case BuiltinTypeSpec.Type.UShort:
3805 underlying_type = rc.BuiltinTypes.Int;
3809 if (expr.Type.IsNullableType)
3810 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
3812 if (expr.Type == underlying_type)
3815 return EmptyCast.Create (expr, underlying_type);
3818 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3821 // U operator - (E e, E f)
3822 // E operator - (E e, U x) // Internal decomposition operator
3823 // E operator - (U x, E e) // Internal decomposition operator
3825 // E operator + (E e, U x)
3826 // E operator + (U x, E e)
3835 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
3841 if (!enum_type.IsNullableType) {
3842 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
3844 if (oper == Operator.Subtraction)
3845 expr = ConvertEnumSubtractionResult (rc, expr);
3847 expr = ConvertEnumAdditionalResult (expr, enum_type);
3849 AddEnumResultCast (expr.Type);
3854 enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
3857 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
3859 if (oper == Operator.Subtraction)
3860 expr = ConvertEnumSubtractionResult (rc, expr);
3862 expr = ConvertEnumAdditionalResult (expr, enum_type);
3864 AddEnumResultCast (expr.Type);
3870 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
3872 return EmptyCast.Create (expr, enumType);
3875 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
3878 // Enumeration subtraction has different result type based on
3881 TypeSpec result_type;
3882 if (left.Type == right.Type) {
3883 var c = right as EnumConstant;
3884 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
3886 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
3887 // E which is not what expressions E - 1 or 0 - E return
3889 result_type = left.Type;
3891 result_type = left.Type.IsNullableType ?
3892 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
3893 EnumSpec.GetUnderlyingType (left.Type);
3896 if (IsEnumOrNullableEnum (left.Type)) {
3897 result_type = left.Type;
3899 result_type = right.Type;
3902 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
3903 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
3906 return EmptyCast.Create (expr, result_type);
3909 void AddEnumResultCast (TypeSpec type)
3911 if (type.IsNullableType)
3912 type = Nullable.NullableInfo.GetUnderlyingType (type);
3915 type = EnumSpec.GetUnderlyingType (type);
3917 switch (type.BuiltinType) {
3918 case BuiltinTypeSpec.Type.SByte:
3919 enum_conversion = ConvCast.Mode.I4_I1;
3921 case BuiltinTypeSpec.Type.Byte:
3922 enum_conversion = ConvCast.Mode.I4_U1;
3924 case BuiltinTypeSpec.Type.Short:
3925 enum_conversion = ConvCast.Mode.I4_I2;
3927 case BuiltinTypeSpec.Type.UShort:
3928 enum_conversion = ConvCast.Mode.I4_U2;
3934 // Equality operators rules
3936 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
3939 type = ec.BuiltinTypes.Bool;
3940 bool no_arg_conv = false;
3942 if (!primitives_only) {
3945 // a, Both operands are reference-type values or the value null
3946 // b, One operand is a value of type T where T is a type-parameter and
3947 // the other operand is the value null. Furthermore T does not have the
3948 // value type constraint
3950 // LAMESPEC: Very confusing details in the specification, basically any
3951 // reference like type-parameter is allowed
3953 var tparam_l = l as TypeParameterSpec;
3954 var tparam_r = r as TypeParameterSpec;
3955 if (tparam_l != null) {
3956 if (right is NullLiteral) {
3957 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3960 left = new BoxedCast (left, ec.BuiltinTypes.Object);
3964 if (!tparam_l.IsReferenceType)
3967 l = tparam_l.GetEffectiveBase ();
3968 left = new BoxedCast (left, l);
3969 } else if (left is NullLiteral && tparam_r == null) {
3970 if (TypeSpec.IsReferenceType (r))
3973 if (r.Kind == MemberKind.InternalCompilerType)
3977 if (tparam_r != null) {
3978 if (left is NullLiteral) {
3979 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
3982 right = new BoxedCast (right, ec.BuiltinTypes.Object);
3986 if (!tparam_r.IsReferenceType)
3989 r = tparam_r.GetEffectiveBase ();
3990 right = new BoxedCast (right, r);
3991 } else if (right is NullLiteral) {
3992 if (TypeSpec.IsReferenceType (l))
3995 if (l.Kind == MemberKind.InternalCompilerType)
4000 // LAMESPEC: method groups can be compared when they convert to other side delegate
4003 if (right.eclass == ExprClass.MethodGroup) {
4004 result = Convert.ImplicitConversion (ec, right, l, loc);
4010 } else if (r.IsDelegate && l != r) {
4013 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4014 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4021 no_arg_conv = l == r && !l.IsStruct;
4026 // bool operator != (string a, string b)
4027 // bool operator == (string a, string b)
4029 // bool operator != (Delegate a, Delegate b)
4030 // bool operator == (Delegate a, Delegate b)
4032 // bool operator != (bool a, bool b)
4033 // bool operator == (bool a, bool b)
4035 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4036 // they implement an implicit conversion to any of types above. This does
4037 // not apply when both operands are of same reference type
4039 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4040 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4045 // Now try lifted version of predefined operators
4047 if (no_arg_conv && !l.IsNullableType) {
4049 // Optimizes cases which won't match
4052 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4058 // The == and != operators permit one operand to be a value of a nullable
4059 // type and the other to be the null literal, even if no predefined or user-defined
4060 // operator (in unlifted or lifted form) exists for the operation.
4062 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4063 var lifted = new Nullable.LiftedBinaryOperator (this);
4065 lifted.Right = right;
4066 return lifted.Resolve (ec);
4071 // bool operator != (object a, object b)
4072 // bool operator == (object a, object b)
4074 // An explicit reference conversion exists from the
4075 // type of either operand to the type of the other operand.
4078 // Optimize common path
4080 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4083 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4084 !Convert.ExplicitReferenceConversionExists (r, l))
4087 // Reject allowed explicit conversions like int->object
4088 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4091 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4092 ec.Report.Warning (253, 2, loc,
4093 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4094 l.GetSignatureForError ());
4096 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4097 ec.Report.Warning (252, 2, loc,
4098 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4099 r.GetSignatureForError ());
4105 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4108 // bool operator == (void* x, void* y);
4109 // bool operator != (void* x, void* y);
4110 // bool operator < (void* x, void* y);
4111 // bool operator > (void* x, void* y);
4112 // bool operator <= (void* x, void* y);
4113 // bool operator >= (void* x, void* y);
4115 if ((oper & Operator.ComparisonMask) != 0) {
4118 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4125 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4131 type = ec.BuiltinTypes.Bool;
4135 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4139 // Build-in operators method overloading
4141 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4143 PredefinedOperator best_operator = null;
4144 TypeSpec l = left.Type;
4145 TypeSpec r = right.Type;
4146 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4148 foreach (PredefinedOperator po in operators) {
4149 if ((po.OperatorsMask & oper_mask) == 0)
4152 if (primitives_only) {
4153 if (!po.IsPrimitiveApplicable (l, r))
4156 if (!po.IsApplicable (ec, left, right))
4160 if (best_operator == null) {
4162 if (primitives_only)
4168 best_operator = po.ResolveBetterOperator (ec, best_operator);
4170 if (best_operator == null) {
4171 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4172 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4179 if (best_operator == null)
4182 return best_operator.ConvertResult (ec, this);
4186 // Optimize & constant expressions with 0 value
4188 Expression OptimizeAndOperation (Expression expr)
4190 Constant rc = right as Constant;
4191 Constant lc = left as Constant;
4192 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4194 // The result is a constant with side-effect
4196 Constant side_effect = rc == null ?
4197 new SideEffectConstant (lc, right, loc) :
4198 new SideEffectConstant (rc, left, loc);
4200 return ReducedExpression.Create (side_effect, expr);
4207 // Value types can be compared with the null literal because of the lifting
4208 // language rules. However the result is always true or false.
4210 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4212 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4213 type = rc.BuiltinTypes.Bool;
4217 // FIXME: Handle side effect constants
4218 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4220 if ((Oper & Operator.EqualityMask) != 0) {
4221 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4222 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4224 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4225 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4232 // Performs user-operator overloading
4234 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4236 Expression oper_expr;
4238 var op = ConvertBinaryToUserOperator (oper);
4240 if (l.IsNullableType)
4241 l = Nullable.NullableInfo.GetUnderlyingType (l);
4243 if (r.IsNullableType)
4244 r = Nullable.NullableInfo.GetUnderlyingType (r);
4246 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
4247 IList<MemberSpec> right_operators = null;
4250 right_operators = MemberCache.GetUserOperator (r, op, false);
4251 if (right_operators == null && left_operators == null)
4253 } else if (left_operators == null) {
4257 Arguments args = new Arguments (2);
4258 Argument larg = new Argument (left);
4260 Argument rarg = new Argument (right);
4264 // User-defined operator implementations always take precedence
4265 // over predefined operator implementations
4267 if (left_operators != null && right_operators != null) {
4268 left_operators = CombineUserOperators (left_operators, right_operators);
4269 } else if (right_operators != null) {
4270 left_operators = right_operators;
4273 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
4274 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
4276 var res = new OverloadResolver (left_operators, restr, loc);
4278 var oper_method = res.ResolveOperator (rc, ref args);
4279 if (oper_method == null) {
4281 // Logical && and || cannot be lifted
4283 if ((oper & Operator.LogicalMask) != 0)
4287 // Apply lifted user operators only for liftable types. Implicit conversion
4288 // to nullable types is not allowed
4290 if (!IsLiftedOperatorApplicable ())
4293 // TODO: Cache the result in module container
4294 var lifted_methods = CreateLiftedOperators (rc, left_operators);
4295 if (lifted_methods == null)
4298 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
4300 oper_method = res.ResolveOperator (rc, ref args);
4301 if (oper_method == null)
4304 MethodSpec best_original = null;
4305 foreach (MethodSpec ms in left_operators) {
4306 if (ms.MemberDefinition == oper_method.MemberDefinition) {
4312 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4314 // Expression trees use lifted notation in this case
4316 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
4317 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
4320 var ptypes = best_original.Parameters.Types;
4322 if (left.IsNull || right.IsNull) {
4324 // The lifted operator produces the value false if one or both operands are null for
4325 // relational operators.
4327 if ((oper & Operator.ComparisonMask) != 0) {
4329 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
4330 // because return type is actually bool
4332 // For some reason CSC does not report this warning for equality operators
4334 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
4337 // The lifted operator produces a null value if one or both operands are null
4339 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
4340 type = oper_method.ReturnType;
4341 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4345 type = oper_method.ReturnType;
4346 var lifted = new Nullable.LiftedBinaryOperator (this);
4347 lifted.UserOperator = best_original;
4349 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
4350 lifted.UnwrapLeft = new Nullable.Unwrap (left);
4353 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
4354 lifted.UnwrapRight = new Nullable.Unwrap (right);
4357 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
4358 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
4360 return lifted.Resolve (rc);
4363 if ((oper & Operator.LogicalMask) != 0) {
4364 // TODO: CreateExpressionTree is allocated every time
4365 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
4366 oper == Operator.LogicalAnd, loc).Resolve (rc);
4368 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
4371 this.left = larg.Expr;
4372 this.right = rarg.Expr;
4377 bool IsLiftedOperatorApplicable ()
4379 if (left.Type.IsNullableType) {
4380 if ((oper & Operator.EqualityMask) != 0)
4381 return !right.IsNull;
4386 if (right.Type.IsNullableType) {
4387 if ((oper & Operator.EqualityMask) != 0)
4388 return !left.IsNull;
4393 if (TypeSpec.IsValueType (left.Type))
4394 return right.IsNull;
4396 if (TypeSpec.IsValueType (right.Type))
4402 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
4404 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4405 if (nullable_type == null)
4409 // Lifted operators permit predefined and user-defined operators that operate
4410 // on non-nullable value types to also be used with nullable forms of those types.
4411 // Lifted operators are constructed from predefined and user-defined operators
4412 // that meet certain requirements
4414 List<MemberSpec> lifted = null;
4415 foreach (MethodSpec oper in operators) {
4417 if ((Oper & Operator.ComparisonMask) != 0) {
4419 // Result type must be of type bool for lifted comparison operators
4421 rt = oper.ReturnType;
4422 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
4425 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
4431 var ptypes = oper.Parameters.Types;
4432 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
4436 // LAMESPEC: I am not sure why but for equality operators to be lifted
4437 // both types have to match
4439 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
4443 lifted = new List<MemberSpec> ();
4446 // The lifted form is constructed by adding a single ? modifier to each operand and
4447 // result type except for comparison operators where return type is bool
4450 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
4452 var parameters = ParametersCompiled.CreateFullyResolved (
4453 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
4454 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
4456 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
4457 rt, parameters, oper.Modifiers);
4459 lifted.Add (lifted_op);
4466 // Merge two sets of user operators into one, they are mostly distinguish
4467 // except when they share base type and it contains an operator
4469 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
4471 var combined = new List<MemberSpec> (left.Count + right.Count);
4472 combined.AddRange (left);
4473 foreach (var r in right) {
4475 foreach (var l in left) {
4476 if (l.DeclaringType == r.DeclaringType) {
4489 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
4491 if (c is IntegralConstant || c is CharConstant) {
4493 c.ConvertExplicitly (true, type);
4494 } catch (OverflowException) {
4495 ec.Report.Warning (652, 2, loc,
4496 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
4497 type.GetSignatureForError ());
4503 /// EmitBranchable is called from Statement.EmitBoolExpression in the
4504 /// context of a conditional bool expression. This function will return
4505 /// false if it is was possible to use EmitBranchable, or true if it was.
4507 /// The expression's code is generated, and we will generate a branch to `target'
4508 /// if the resulting expression value is equal to isTrue
4510 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
4512 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4513 left = left.EmitToField (ec);
4515 if ((oper & Operator.LogicalMask) == 0) {
4516 right = right.EmitToField (ec);
4521 // This is more complicated than it looks, but its just to avoid
4522 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
4523 // but on top of that we want for == and != to use a special path
4524 // if we are comparing against null
4526 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
4527 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
4530 // put the constant on the rhs, for simplicity
4532 if (left is Constant) {
4533 Expression swap = right;
4539 // brtrue/brfalse works with native int only
4541 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4542 left.EmitBranchable (ec, target, my_on_true);
4545 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
4546 // right is a boolean, and it's not 'false' => it is 'true'
4547 left.EmitBranchable (ec, target, !my_on_true);
4551 } else if (oper == Operator.LogicalAnd) {
4554 Label tests_end = ec.DefineLabel ();
4556 left.EmitBranchable (ec, tests_end, false);
4557 right.EmitBranchable (ec, target, true);
4558 ec.MarkLabel (tests_end);
4561 // This optimizes code like this
4562 // if (true && i > 4)
4564 if (!(left is Constant))
4565 left.EmitBranchable (ec, target, false);
4567 if (!(right is Constant))
4568 right.EmitBranchable (ec, target, false);
4573 } else if (oper == Operator.LogicalOr){
4575 left.EmitBranchable (ec, target, true);
4576 right.EmitBranchable (ec, target, true);
4579 Label tests_end = ec.DefineLabel ();
4580 left.EmitBranchable (ec, tests_end, true);
4581 right.EmitBranchable (ec, target, false);
4582 ec.MarkLabel (tests_end);
4587 } else if ((oper & Operator.ComparisonMask) == 0) {
4588 base.EmitBranchable (ec, target, on_true);
4595 TypeSpec t = left.Type;
4596 bool is_float = IsFloat (t);
4597 bool is_unsigned = is_float || IsUnsigned (t);
4600 case Operator.Equality:
4602 ec.Emit (OpCodes.Beq, target);
4604 ec.Emit (OpCodes.Bne_Un, target);
4607 case Operator.Inequality:
4609 ec.Emit (OpCodes.Bne_Un, target);
4611 ec.Emit (OpCodes.Beq, target);
4614 case Operator.LessThan:
4616 if (is_unsigned && !is_float)
4617 ec.Emit (OpCodes.Blt_Un, target);
4619 ec.Emit (OpCodes.Blt, target);
4622 ec.Emit (OpCodes.Bge_Un, target);
4624 ec.Emit (OpCodes.Bge, target);
4627 case Operator.GreaterThan:
4629 if (is_unsigned && !is_float)
4630 ec.Emit (OpCodes.Bgt_Un, target);
4632 ec.Emit (OpCodes.Bgt, target);
4635 ec.Emit (OpCodes.Ble_Un, target);
4637 ec.Emit (OpCodes.Ble, target);
4640 case Operator.LessThanOrEqual:
4642 if (is_unsigned && !is_float)
4643 ec.Emit (OpCodes.Ble_Un, target);
4645 ec.Emit (OpCodes.Ble, target);
4648 ec.Emit (OpCodes.Bgt_Un, target);
4650 ec.Emit (OpCodes.Bgt, target);
4654 case Operator.GreaterThanOrEqual:
4656 if (is_unsigned && !is_float)
4657 ec.Emit (OpCodes.Bge_Un, target);
4659 ec.Emit (OpCodes.Bge, target);
4662 ec.Emit (OpCodes.Blt_Un, target);
4664 ec.Emit (OpCodes.Blt, target);
4667 throw new InternalErrorException (oper.ToString ());
4671 public override void Emit (EmitContext ec)
4673 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
4674 left = left.EmitToField (ec);
4676 if ((oper & Operator.LogicalMask) == 0) {
4677 right = right.EmitToField (ec);
4682 // Handle short-circuit operators differently
4685 if ((oper & Operator.LogicalMask) != 0) {
4686 Label load_result = ec.DefineLabel ();
4687 Label end = ec.DefineLabel ();
4689 bool is_or = oper == Operator.LogicalOr;
4690 left.EmitBranchable (ec, load_result, is_or);
4692 ec.Emit (OpCodes.Br_S, end);
4694 ec.MarkLabel (load_result);
4695 ec.EmitInt (is_or ? 1 : 0);
4701 // Optimize zero-based operations which cannot be optimized at expression level
4703 if (oper == Operator.Subtraction) {
4704 var lc = left as IntegralConstant;
4705 if (lc != null && lc.IsDefaultValue) {
4707 ec.Emit (OpCodes.Neg);
4712 EmitOperator (ec, left, right);
4715 public void EmitOperator (EmitContext ec, Expression left, Expression right)
4720 EmitOperatorOpcode (ec, oper, left.Type, right);
4723 // Emit result enumerable conversion this way because it's quite complicated get it
4724 // to resolved tree because expression tree cannot see it.
4726 if (enum_conversion != 0)
4727 ConvCast.Emit (ec, enum_conversion);
4730 public override void EmitSideEffect (EmitContext ec)
4732 if ((oper & Operator.LogicalMask) != 0 ||
4733 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
4734 base.EmitSideEffect (ec);
4736 left.EmitSideEffect (ec);
4737 right.EmitSideEffect (ec);
4741 public override Expression EmitToField (EmitContext ec)
4743 if ((oper & Operator.LogicalMask) == 0) {
4744 var await_expr = left as Await;
4745 if (await_expr != null && right.IsSideEffectFree) {
4746 await_expr.Statement.EmitPrologue (ec);
4747 left = await_expr.Statement.GetResultExpression (ec);
4751 await_expr = right as Await;
4752 if (await_expr != null && left.IsSideEffectFree) {
4753 await_expr.Statement.EmitPrologue (ec);
4754 right = await_expr.Statement.GetResultExpression (ec);
4759 return base.EmitToField (ec);
4762 protected override void CloneTo (CloneContext clonectx, Expression t)
4764 Binary target = (Binary) t;
4766 target.left = left.Clone (clonectx);
4767 target.right = right.Clone (clonectx);
4770 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
4772 Arguments binder_args = new Arguments (4);
4774 MemberAccess sle = new MemberAccess (new MemberAccess (
4775 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
4777 CSharpBinderFlags flags = 0;
4778 if (ec.HasSet (ResolveContext.Options.CheckedScope))
4779 flags = CSharpBinderFlags.CheckedContext;
4781 if ((oper & Operator.LogicalMask) != 0)
4782 flags |= CSharpBinderFlags.BinaryOperationLogical;
4784 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
4785 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
4786 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
4787 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
4789 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
4792 public override Expression CreateExpressionTree (ResolveContext ec)
4794 return CreateExpressionTree (ec, null);
4797 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
4800 bool lift_arg = false;
4803 case Operator.Addition:
4804 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4805 method_name = "AddChecked";
4807 method_name = "Add";
4809 case Operator.BitwiseAnd:
4810 method_name = "And";
4812 case Operator.BitwiseOr:
4815 case Operator.Division:
4816 method_name = "Divide";
4818 case Operator.Equality:
4819 method_name = "Equal";
4822 case Operator.ExclusiveOr:
4823 method_name = "ExclusiveOr";
4825 case Operator.GreaterThan:
4826 method_name = "GreaterThan";
4829 case Operator.GreaterThanOrEqual:
4830 method_name = "GreaterThanOrEqual";
4833 case Operator.Inequality:
4834 method_name = "NotEqual";
4837 case Operator.LeftShift:
4838 method_name = "LeftShift";
4840 case Operator.LessThan:
4841 method_name = "LessThan";
4844 case Operator.LessThanOrEqual:
4845 method_name = "LessThanOrEqual";
4848 case Operator.LogicalAnd:
4849 method_name = "AndAlso";
4851 case Operator.LogicalOr:
4852 method_name = "OrElse";
4854 case Operator.Modulus:
4855 method_name = "Modulo";
4857 case Operator.Multiply:
4858 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4859 method_name = "MultiplyChecked";
4861 method_name = "Multiply";
4863 case Operator.RightShift:
4864 method_name = "RightShift";
4866 case Operator.Subtraction:
4867 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
4868 method_name = "SubtractChecked";
4870 method_name = "Subtract";
4874 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
4877 Arguments args = new Arguments (2);
4878 args.Add (new Argument (left.CreateExpressionTree (ec)));
4879 args.Add (new Argument (right.CreateExpressionTree (ec)));
4880 if (method != null) {
4882 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
4884 args.Add (new Argument (method));
4887 return CreateExpressionFactoryCall (ec, method_name, args);
4890 public override object Accept (StructuralVisitor visitor)
4892 return visitor.Visit (this);
4898 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4899 // b, c, d... may be strings or objects.
4901 public class StringConcat : Expression
4903 Arguments arguments;
4905 StringConcat (Location loc)
4908 arguments = new Arguments (2);
4911 public override bool ContainsEmitWithAwait ()
4913 return arguments.ContainsEmitWithAwait ();
4916 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4918 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4919 throw new ArgumentException ();
4921 var s = new StringConcat (loc);
4922 s.type = rc.BuiltinTypes.String;
4923 s.eclass = ExprClass.Value;
4925 s.Append (rc, left);
4926 s.Append (rc, right);
4930 public override Expression CreateExpressionTree (ResolveContext ec)
4932 Argument arg = arguments [0];
4933 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4937 // Creates nested calls tree from an array of arguments used for IL emit
4939 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4941 Arguments concat_args = new Arguments (2);
4942 Arguments add_args = new Arguments (3);
4944 concat_args.Add (left);
4945 add_args.Add (new Argument (left_etree));
4947 concat_args.Add (arguments [pos]);
4948 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4950 var methods = GetConcatMethodCandidates ();
4951 if (methods == null)
4954 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4955 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4959 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4961 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4962 if (++pos == arguments.Count)
4965 left = new Argument (new EmptyExpression (method.ReturnType));
4966 return CreateExpressionAddCall (ec, left, expr, pos);
4969 protected override Expression DoResolve (ResolveContext ec)
4974 void Append (ResolveContext rc, Expression operand)
4979 StringConstant sc = operand as StringConstant;
4981 if (arguments.Count != 0) {
4982 Argument last_argument = arguments [arguments.Count - 1];
4983 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4984 if (last_expr_constant != null) {
4985 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4991 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
4993 StringConcat concat_oper = operand as StringConcat;
4994 if (concat_oper != null) {
4995 arguments.AddRange (concat_oper.arguments);
5000 arguments.Add (new Argument (operand));
5003 IList<MemberSpec> GetConcatMethodCandidates ()
5005 return MemberCache.FindMembers (type, "Concat", true);
5008 public override void Emit (EmitContext ec)
5010 // Optimize by removing any extra null arguments, they are no-op
5011 for (int i = 0; i < arguments.Count; ++i) {
5012 if (arguments[i].Expr is NullConstant)
5013 arguments.RemoveAt (i--);
5016 var members = GetConcatMethodCandidates ();
5017 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5018 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5019 if (method != null) {
5020 var call = new CallEmitter ();
5021 call.EmitPredefined (ec, method, arguments);
5025 public override void FlowAnalysis (FlowAnalysisContext fc)
5027 arguments.FlowAnalysis (fc);
5030 public override SLE.Expression MakeExpression (BuilderContext ctx)
5032 if (arguments.Count != 2)
5033 throw new NotImplementedException ("arguments.Count != 2");
5035 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5036 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5041 // User-defined conditional logical operator
5043 public class ConditionalLogicalOperator : UserOperatorCall
5045 readonly bool is_and;
5046 Expression oper_expr;
5048 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5049 : base (oper, arguments, expr_tree, loc)
5051 this.is_and = is_and;
5052 eclass = ExprClass.Unresolved;
5055 protected override Expression DoResolve (ResolveContext ec)
5057 AParametersCollection pd = oper.Parameters;
5058 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5059 ec.Report.Error (217, loc,
5060 "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",
5061 oper.GetSignatureForError ());
5065 Expression left_dup = new EmptyExpression (type);
5066 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5067 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5068 if (op_true == null || op_false == null) {
5069 ec.Report.Error (218, loc,
5070 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5071 type.GetSignatureForError (), oper.GetSignatureForError ());
5075 oper_expr = is_and ? op_false : op_true;
5076 eclass = ExprClass.Value;
5080 public override void Emit (EmitContext ec)
5082 Label end_target = ec.DefineLabel ();
5085 // Emit and duplicate left argument
5087 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5088 if (right_contains_await) {
5089 arguments[0] = arguments[0].EmitToField (ec, false);
5090 arguments[0].Expr.Emit (ec);
5092 arguments[0].Expr.Emit (ec);
5093 ec.Emit (OpCodes.Dup);
5094 arguments.RemoveAt (0);
5097 oper_expr.EmitBranchable (ec, end_target, true);
5101 if (right_contains_await) {
5103 // Special handling when right expression contains await and left argument
5104 // could not be left on stack before logical branch
5106 Label skip_left_load = ec.DefineLabel ();
5107 ec.Emit (OpCodes.Br_S, skip_left_load);
5108 ec.MarkLabel (end_target);
5109 arguments[0].Expr.Emit (ec);
5110 ec.MarkLabel (skip_left_load);
5112 ec.MarkLabel (end_target);
5117 public class PointerArithmetic : Expression {
5118 Expression left, right;
5119 readonly Binary.Operator op;
5122 // We assume that `l' is always a pointer
5124 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5133 public override bool ContainsEmitWithAwait ()
5135 throw new NotImplementedException ();
5138 public override Expression CreateExpressionTree (ResolveContext ec)
5140 Error_PointerInsideExpressionTree (ec);
5144 protected override Expression DoResolve (ResolveContext ec)
5146 eclass = ExprClass.Variable;
5148 var pc = left.Type as PointerContainer;
5149 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5150 Error_VoidPointerOperation (ec);
5157 public override void Emit (EmitContext ec)
5159 TypeSpec op_type = left.Type;
5161 // It must be either array or fixed buffer
5163 if (TypeManager.HasElementType (op_type)) {
5164 element = TypeManager.GetElementType (op_type);
5166 FieldExpr fe = left as FieldExpr;
5168 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5173 int size = BuiltinTypeSpec.GetSize(element);
5174 TypeSpec rtype = right.Type;
5176 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5178 // handle (pointer - pointer)
5182 ec.Emit (OpCodes.Sub);
5186 ec.Emit (OpCodes.Sizeof, element);
5189 ec.Emit (OpCodes.Div);
5191 ec.Emit (OpCodes.Conv_I8);
5194 // handle + and - on (pointer op int)
5196 Constant left_const = left as Constant;
5197 if (left_const != null) {
5199 // Optimize ((T*)null) pointer operations
5201 if (left_const.IsDefaultValue) {
5202 left = EmptyExpression.Null;
5210 var right_const = right as Constant;
5211 if (right_const != null) {
5213 // Optimize 0-based arithmetic
5215 if (right_const.IsDefaultValue)
5219 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5221 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5223 // TODO: Should be the checks resolve context sensitive?
5224 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5225 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5231 switch (rtype.BuiltinType) {
5232 case BuiltinTypeSpec.Type.SByte:
5233 case BuiltinTypeSpec.Type.Byte:
5234 case BuiltinTypeSpec.Type.Short:
5235 case BuiltinTypeSpec.Type.UShort:
5236 ec.Emit (OpCodes.Conv_I);
5238 case BuiltinTypeSpec.Type.UInt:
5239 ec.Emit (OpCodes.Conv_U);
5243 if (right_const == null && size != 1){
5245 ec.Emit (OpCodes.Sizeof, element);
5248 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5249 ec.Emit (OpCodes.Conv_I8);
5251 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
5254 if (left_const == null) {
5255 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
5256 ec.Emit (OpCodes.Conv_I);
5257 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
5258 ec.Emit (OpCodes.Conv_U);
5260 Binary.EmitOperatorOpcode (ec, op, op_type, right);
5267 // A boolean-expression is an expression that yields a result
5270 public class BooleanExpression : ShimExpression
5272 public BooleanExpression (Expression expr)
5275 this.loc = expr.Location;
5278 public override Expression CreateExpressionTree (ResolveContext ec)
5280 // TODO: We should emit IsTrue (v4) instead of direct user operator
5281 // call but that would break csc compatibility
5282 return base.CreateExpressionTree (ec);
5285 protected override Expression DoResolve (ResolveContext ec)
5287 // A boolean-expression is required to be of a type
5288 // that can be implicitly converted to bool or of
5289 // a type that implements operator true
5291 expr = expr.Resolve (ec);
5295 Assign ass = expr as Assign;
5296 if (ass != null && ass.Source is Constant) {
5297 ec.Report.Warning (665, 3, loc,
5298 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
5301 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
5304 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5305 Arguments args = new Arguments (1);
5306 args.Add (new Argument (expr));
5307 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
5310 type = ec.BuiltinTypes.Bool;
5311 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
5312 if (converted != null)
5316 // If no implicit conversion to bool exists, try using `operator true'
5318 converted = GetOperatorTrue (ec, expr, loc);
5319 if (converted == null) {
5320 expr.Error_ValueCannotBeConverted (ec, type, false);
5327 public override object Accept (StructuralVisitor visitor)
5329 return visitor.Visit (this);
5333 public class BooleanExpressionFalse : Unary
5335 public BooleanExpressionFalse (Expression expr)
5336 : base (Operator.LogicalNot, expr, expr.Location)
5340 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
5342 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
5347 /// Implements the ternary conditional operator (?:)
5349 public class Conditional : Expression {
5350 Expression expr, true_expr, false_expr;
5352 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
5355 this.true_expr = true_expr;
5356 this.false_expr = false_expr;
5362 public Expression Expr {
5368 public Expression TrueExpr {
5374 public Expression FalseExpr {
5382 public override bool ContainsEmitWithAwait ()
5384 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
5387 public override Expression CreateExpressionTree (ResolveContext ec)
5389 Arguments args = new Arguments (3);
5390 args.Add (new Argument (expr.CreateExpressionTree (ec)));
5391 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
5392 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
5393 return CreateExpressionFactoryCall (ec, "Condition", args);
5396 protected override Expression DoResolve (ResolveContext ec)
5398 expr = expr.Resolve (ec);
5399 true_expr = true_expr.Resolve (ec);
5400 false_expr = false_expr.Resolve (ec);
5402 if (true_expr == null || false_expr == null || expr == null)
5405 eclass = ExprClass.Value;
5406 TypeSpec true_type = true_expr.Type;
5407 TypeSpec false_type = false_expr.Type;
5411 // First, if an implicit conversion exists from true_expr
5412 // to false_expr, then the result type is of type false_expr.Type
5414 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
5415 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
5416 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5418 // Check if both can convert implicitly to each other's type
5422 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
5423 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
5425 // LAMESPEC: There seems to be hardcoded promotition to int type when
5426 // both sides are numeric constants and one side is int constant and
5427 // other side is numeric constant convertible to int.
5429 // var res = condition ? (short)1 : 1;
5431 // Type of res is int even if according to the spec the conversion is
5432 // ambiguous because 1 literal can be converted to short.
5434 if (conv_false_expr != null) {
5435 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
5437 conv_false_expr = null;
5438 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
5439 conv_false_expr = null;
5443 if (conv_false_expr != null) {
5444 ec.Report.Error (172, true_expr.Location,
5445 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
5446 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5451 if (true_expr.Type != type)
5452 true_expr = EmptyCast.Create (true_expr, type);
5453 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
5456 ec.Report.Error (173, true_expr.Location,
5457 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
5458 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
5463 Constant c = expr as Constant;
5465 bool is_false = c.IsDefaultValue;
5468 // Don't issue the warning for constant expressions
5470 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
5471 // CSC: Missing warning
5472 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
5475 return ReducedExpression.Create (
5476 is_false ? false_expr : true_expr, this,
5477 false_expr is Constant && true_expr is Constant).Resolve (ec);
5483 public override void Emit (EmitContext ec)
5485 Label false_target = ec.DefineLabel ();
5486 Label end_target = ec.DefineLabel ();
5488 expr.EmitBranchable (ec, false_target, false);
5489 true_expr.Emit (ec);
5492 // Verifier doesn't support interface merging. When there are two types on
5493 // the stack without common type hint and the common type is an interface.
5494 // Use temporary local to give verifier hint on what type to unify the stack
5496 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
5497 var temp = ec.GetTemporaryLocal (type);
5498 ec.Emit (OpCodes.Stloc, temp);
5499 ec.Emit (OpCodes.Ldloc, temp);
5500 ec.FreeTemporaryLocal (temp, type);
5503 ec.Emit (OpCodes.Br, end_target);
5504 ec.MarkLabel (false_target);
5505 false_expr.Emit (ec);
5506 ec.MarkLabel (end_target);
5509 public override void FlowAnalysis (FlowAnalysisContext fc)
5511 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5513 expr.FlowAnalysis (fc);
5514 var da_true = fc.DefiniteAssignmentOnTrue;
5515 var da_false = fc.DefiniteAssignmentOnFalse;
5517 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_true);
5518 true_expr.FlowAnalysis (fc);
5519 var true_fc = fc.DefiniteAssignment;
5521 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_false);
5522 false_expr.FlowAnalysis (fc);
5524 fc.DefiniteAssignment &= true_fc;
5525 if (fc.DefiniteAssignmentOnTrue != null)
5526 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
5527 if (fc.DefiniteAssignmentOnFalse != null)
5528 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
5531 protected override void CloneTo (CloneContext clonectx, Expression t)
5533 Conditional target = (Conditional) t;
5535 target.expr = expr.Clone (clonectx);
5536 target.true_expr = true_expr.Clone (clonectx);
5537 target.false_expr = false_expr.Clone (clonectx);
5541 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
5543 LocalTemporary temp;
5546 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
5547 public abstract void SetHasAddressTaken ();
5549 public abstract bool IsLockedByStatement { get; set; }
5551 public abstract bool IsFixed { get; }
5552 public abstract bool IsRef { get; }
5553 public abstract string Name { get; }
5556 // Variable IL data, it has to be protected to encapsulate hoisted variables
5558 protected abstract ILocalVariable Variable { get; }
5561 // Variable flow-analysis data
5563 public abstract VariableInfo VariableInfo { get; }
5566 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5568 HoistedVariable hv = GetHoistedVariable (ec);
5570 hv.AddressOf (ec, mode);
5574 Variable.EmitAddressOf (ec);
5577 public override bool ContainsEmitWithAwait ()
5582 public override Expression CreateExpressionTree (ResolveContext ec)
5584 HoistedVariable hv = GetHoistedVariable (ec);
5586 return hv.CreateExpressionTree ();
5588 Arguments arg = new Arguments (1);
5589 arg.Add (new Argument (this));
5590 return CreateExpressionFactoryCall (ec, "Constant", arg);
5593 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
5595 if (IsLockedByStatement) {
5596 rc.Report.Warning (728, 2, loc,
5597 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
5604 public override void Emit (EmitContext ec)
5609 public override void EmitSideEffect (EmitContext ec)
5615 // This method is used by parameters that are references, that are
5616 // being passed as references: we only want to pass the pointer (that
5617 // is already stored in the parameter, not the address of the pointer,
5618 // and not the value of the variable).
5620 public void EmitLoad (EmitContext ec)
5625 public void Emit (EmitContext ec, bool leave_copy)
5627 HoistedVariable hv = GetHoistedVariable (ec);
5629 hv.Emit (ec, leave_copy);
5637 // If we are a reference, we loaded on the stack a pointer
5638 // Now lets load the real value
5640 ec.EmitLoadFromPtr (type);
5644 ec.Emit (OpCodes.Dup);
5647 temp = new LocalTemporary (Type);
5653 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
5654 bool prepare_for_load)
5656 HoistedVariable hv = GetHoistedVariable (ec);
5658 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
5662 New n_source = source as New;
5663 if (n_source != null) {
5664 if (!n_source.Emit (ec, this)) {
5668 ec.EmitLoadFromPtr (type);
5680 ec.Emit (OpCodes.Dup);
5682 temp = new LocalTemporary (Type);
5688 ec.EmitStoreFromPtr (type);
5690 Variable.EmitAssign (ec);
5698 public override Expression EmitToField (EmitContext ec)
5700 HoistedVariable hv = GetHoistedVariable (ec);
5702 return hv.EmitToField (ec);
5705 return base.EmitToField (ec);
5708 public HoistedVariable GetHoistedVariable (ResolveContext rc)
5710 return GetHoistedVariable (rc.CurrentAnonymousMethod);
5713 public HoistedVariable GetHoistedVariable (EmitContext ec)
5715 return GetHoistedVariable (ec.CurrentAnonymousMethod);
5718 public override string GetSignatureForError ()
5723 public bool IsHoisted {
5724 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
5729 // Resolved reference to a local variable
5731 public class LocalVariableReference : VariableReference
5733 public LocalVariable local_info;
5735 public LocalVariableReference (LocalVariable li, Location l)
5737 this.local_info = li;
5741 public override VariableInfo VariableInfo {
5742 get { return local_info.VariableInfo; }
5745 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5747 return local_info.HoistedVariant;
5753 // A local variable is always fixed
5755 public override bool IsFixed {
5761 public override bool IsLockedByStatement {
5763 return local_info.IsLocked;
5766 local_info.IsLocked = value;
5770 public override bool IsRef {
5771 get { return false; }
5774 public override string Name {
5775 get { return local_info.Name; }
5780 public override void FlowAnalysis (FlowAnalysisContext fc)
5782 VariableInfo variable_info = VariableInfo;
5783 if (variable_info == null)
5786 if (fc.IsDefinitelyAssigned (variable_info))
5789 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
5790 variable_info.SetAssigned (fc.DefiniteAssignment, true);
5793 public override void SetHasAddressTaken ()
5795 local_info.SetHasAddressTaken ();
5798 void DoResolveBase (ResolveContext ec)
5801 // If we are referencing a variable from the external block
5802 // flag it for capturing
5804 if (ec.MustCaptureVariable (local_info)) {
5805 if (local_info.AddressTaken) {
5806 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5807 } else if (local_info.IsFixed) {
5808 ec.Report.Error (1764, loc,
5809 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
5810 GetSignatureForError ());
5813 if (ec.IsVariableCapturingRequired) {
5814 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
5815 storey.CaptureLocalVariable (ec, local_info);
5819 eclass = ExprClass.Variable;
5820 type = local_info.Type;
5823 protected override Expression DoResolve (ResolveContext ec)
5825 local_info.SetIsUsed ();
5831 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
5834 // Don't be too pedantic when variable is used as out param or for some broken code
5835 // which uses property/indexer access to run some initialization
5837 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
5838 local_info.SetIsUsed ();
5840 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
5841 if (rhs == EmptyExpression.LValueMemberAccess) {
5842 // CS1654 already reported
5846 if (rhs == EmptyExpression.OutAccess) {
5847 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
5848 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
5849 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
5850 } else if (rhs == EmptyExpression.UnaryAddress) {
5851 code = 459; msg = "Cannot take the address of {1} `{0}'";
5853 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
5855 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
5859 if (eclass == ExprClass.Unresolved)
5862 return base.DoResolveLValue (ec, rhs);
5865 public override int GetHashCode ()
5867 return local_info.GetHashCode ();
5870 public override bool Equals (object obj)
5872 LocalVariableReference lvr = obj as LocalVariableReference;
5876 return local_info == lvr.local_info;
5879 protected override ILocalVariable Variable {
5880 get { return local_info; }
5883 public override string ToString ()
5885 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
5888 protected override void CloneTo (CloneContext clonectx, Expression t)
5895 /// This represents a reference to a parameter in the intermediate
5898 public class ParameterReference : VariableReference
5900 protected ParametersBlock.ParameterInfo pi;
5902 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
5910 public override bool IsLockedByStatement {
5915 pi.IsLocked = value;
5919 public override bool IsRef {
5920 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
5923 bool HasOutModifier {
5924 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
5927 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5929 return pi.Parameter.HoistedVariant;
5933 // A ref or out parameter is classified as a moveable variable, even
5934 // if the argument given for the parameter is a fixed variable
5936 public override bool IsFixed {
5937 get { return !IsRef; }
5940 public override string Name {
5941 get { return Parameter.Name; }
5944 public Parameter Parameter {
5945 get { return pi.Parameter; }
5948 public override VariableInfo VariableInfo {
5949 get { return pi.VariableInfo; }
5952 protected override ILocalVariable Variable {
5953 get { return Parameter; }
5958 public override void AddressOf (EmitContext ec, AddressOp mode)
5961 // ParameterReferences might already be a reference
5968 base.AddressOf (ec, mode);
5971 public override void SetHasAddressTaken ()
5973 Parameter.HasAddressTaken = true;
5976 bool DoResolveBase (ResolveContext ec)
5978 if (eclass != ExprClass.Unresolved)
5981 type = pi.ParameterType;
5982 eclass = ExprClass.Variable;
5985 // If we are referencing a parameter from the external block
5986 // flag it for capturing
5988 if (ec.MustCaptureVariable (pi)) {
5989 if (Parameter.HasAddressTaken)
5990 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
5993 ec.Report.Error (1628, loc,
5994 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
5995 Name, ec.CurrentAnonymousMethod.ContainerType);
5998 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
5999 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6000 storey.CaptureParameter (ec, pi, this);
6007 public override int GetHashCode ()
6009 return Name.GetHashCode ();
6012 public override bool Equals (object obj)
6014 ParameterReference pr = obj as ParameterReference;
6018 return Name == pr.Name;
6021 protected override void CloneTo (CloneContext clonectx, Expression target)
6027 public override Expression CreateExpressionTree (ResolveContext ec)
6029 HoistedVariable hv = GetHoistedVariable (ec);
6031 return hv.CreateExpressionTree ();
6033 return Parameter.ExpressionTreeVariableReference ();
6036 protected override Expression DoResolve (ResolveContext ec)
6038 if (!DoResolveBase (ec))
6044 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6046 if (!DoResolveBase (ec))
6049 if (Parameter.HoistedVariant != null)
6050 Parameter.HoistedVariant.IsAssigned = true;
6052 return base.DoResolveLValue (ec, right_side);
6055 public override void FlowAnalysis (FlowAnalysisContext fc)
6057 VariableInfo variable_info = VariableInfo;
6058 if (variable_info == null)
6061 if (fc.IsDefinitelyAssigned (variable_info))
6064 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6065 fc.SetVariableAssigned (variable_info);
6070 /// Invocation of methods or delegates.
6072 public class Invocation : ExpressionStatement
6074 protected Arguments arguments;
6075 protected Expression expr;
6076 protected MethodGroupExpr mg;
6078 public Invocation (Expression expr, Arguments arguments)
6081 this.arguments = arguments;
6083 loc = expr.Location;
6088 public Arguments Arguments {
6094 public Expression Exp {
6100 public MethodGroupExpr MethodGroup {
6106 public override Location StartLocation {
6108 return expr.StartLocation;
6114 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6116 if (MethodGroup == null)
6119 var candidate = MethodGroup.BestCandidate;
6120 if (candidate == null || !(candidate.IsStatic || Exp is This))
6123 var args_count = arguments == null ? 0 : arguments.Count;
6124 if (args_count != body.Parameters.Count)
6127 var lambda_parameters = body.Block.Parameters.FixedParameters;
6128 for (int i = 0; i < args_count; ++i) {
6129 var pr = arguments[i].Expr as ParameterReference;
6133 if (lambda_parameters[i] != pr.Parameter)
6136 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6140 var emg = MethodGroup as ExtensionMethodGroupExpr;
6142 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6143 if (candidate.IsGeneric) {
6144 var targs = new TypeExpression [candidate.Arity];
6145 for (int i = 0; i < targs.Length; ++i) {
6146 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6149 mg.SetTypeArguments (null, new TypeArguments (targs));
6158 protected override void CloneTo (CloneContext clonectx, Expression t)
6160 Invocation target = (Invocation) t;
6162 if (arguments != null)
6163 target.arguments = arguments.Clone (clonectx);
6165 target.expr = expr.Clone (clonectx);
6168 public override bool ContainsEmitWithAwait ()
6170 if (arguments != null && arguments.ContainsEmitWithAwait ())
6173 return mg.ContainsEmitWithAwait ();
6176 public override Expression CreateExpressionTree (ResolveContext ec)
6178 Expression instance = mg.IsInstance ?
6179 mg.InstanceExpression.CreateExpressionTree (ec) :
6180 new NullLiteral (loc);
6182 var args = Arguments.CreateForExpressionTree (ec, arguments,
6184 mg.CreateExpressionTree (ec));
6186 return CreateExpressionFactoryCall (ec, "Call", args);
6189 protected override Expression DoResolve (ResolveContext ec)
6191 Expression member_expr;
6192 var atn = expr as ATypeNameExpression;
6194 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
6195 if (member_expr != null)
6196 member_expr = member_expr.Resolve (ec);
6198 member_expr = expr.Resolve (ec);
6201 if (member_expr == null)
6205 // Next, evaluate all the expressions in the argument list
6207 bool dynamic_arg = false;
6208 if (arguments != null)
6209 arguments.Resolve (ec, out dynamic_arg);
6211 TypeSpec expr_type = member_expr.Type;
6212 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6213 return DoResolveDynamic (ec, member_expr);
6215 mg = member_expr as MethodGroupExpr;
6216 Expression invoke = null;
6219 if (expr_type != null && expr_type.IsDelegate) {
6220 invoke = new DelegateInvocation (member_expr, arguments, loc);
6221 invoke = invoke.Resolve (ec);
6222 if (invoke == null || !dynamic_arg)
6225 if (member_expr is RuntimeValueExpression) {
6226 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
6227 member_expr.Type.GetSignatureForError ());
6231 MemberExpr me = member_expr as MemberExpr;
6233 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
6237 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
6238 member_expr.GetSignatureForError ());
6243 if (invoke == null) {
6244 mg = DoResolveOverload (ec);
6250 return DoResolveDynamic (ec, member_expr);
6252 var method = mg.BestCandidate;
6253 type = mg.BestCandidateReturnType;
6255 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
6257 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
6259 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
6263 IsSpecialMethodInvocation (ec, method, loc);
6265 eclass = ExprClass.Value;
6269 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
6272 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
6274 args = dmb.Arguments;
6275 if (arguments != null)
6276 args.AddRange (arguments);
6277 } else if (mg == null) {
6278 if (arguments == null)
6279 args = new Arguments (1);
6283 args.Insert (0, new Argument (memberExpr));
6287 ec.Report.Error (1971, loc,
6288 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
6293 if (arguments == null)
6294 args = new Arguments (1);
6298 MemberAccess ma = expr as MemberAccess;
6300 var left_type = ma.LeftExpression as TypeExpr;
6301 if (left_type != null) {
6302 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6305 // Any value type has to be pass as by-ref to get back the same
6306 // instance on which the member was called
6308 var mod = ma.LeftExpression is IMemoryLocation && TypeSpec.IsValueType (ma.LeftExpression.Type) ?
6309 Argument.AType.Ref : Argument.AType.None;
6310 args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
6312 } else { // is SimpleName
6314 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6316 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
6321 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
6324 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
6326 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
6329 public override void FlowAnalysis (FlowAnalysisContext fc)
6331 if (mg.IsConditionallyExcluded)
6334 mg.FlowAnalysis (fc);
6336 if (arguments != null)
6337 arguments.FlowAnalysis (fc);
6340 public override string GetSignatureForError ()
6342 return mg.GetSignatureForError ();
6346 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
6347 // or the type dynamic, then the member is invocable
6349 public static bool IsMemberInvocable (MemberSpec member)
6351 switch (member.Kind) {
6352 case MemberKind.Event:
6354 case MemberKind.Field:
6355 case MemberKind.Property:
6356 var m = member as IInterfaceMemberSpec;
6357 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6363 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
6365 if (!method.IsReservedMethod)
6368 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
6371 ec.Report.SymbolRelatedToPreviousError (method);
6372 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
6373 method.GetSignatureForError ());
6378 public override void Emit (EmitContext ec)
6380 if (mg.IsConditionallyExcluded)
6383 mg.EmitCall (ec, arguments);
6386 public override void EmitStatement (EmitContext ec)
6391 // Pop the return value if there is one
6393 if (type.Kind != MemberKind.Void)
6394 ec.Emit (OpCodes.Pop);
6397 public override SLE.Expression MakeExpression (BuilderContext ctx)
6399 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
6402 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
6405 throw new NotSupportedException ();
6407 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
6408 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
6412 public override object Accept (StructuralVisitor visitor)
6414 return visitor.Visit (this);
6419 // Implements simple new expression
6421 public class New : ExpressionStatement, IMemoryLocation
6423 protected Arguments arguments;
6426 // During bootstrap, it contains the RequestedType,
6427 // but if `type' is not null, it *might* contain a NewDelegate
6428 // (because of field multi-initialization)
6430 protected Expression RequestedType;
6432 protected MethodSpec method;
6434 public New (Expression requested_type, Arguments arguments, Location l)
6436 RequestedType = requested_type;
6437 this.arguments = arguments;
6442 public Arguments Arguments {
6449 // Returns true for resolved `new S()'
6451 public bool IsDefaultStruct {
6453 return arguments == null && type.IsStruct && GetType () == typeof (New);
6457 public Expression TypeExpression {
6459 return RequestedType;
6466 /// Converts complex core type syntax like 'new int ()' to simple constant
6468 public static Constant Constantify (TypeSpec t, Location loc)
6470 switch (t.BuiltinType) {
6471 case BuiltinTypeSpec.Type.Int:
6472 return new IntConstant (t, 0, loc);
6473 case BuiltinTypeSpec.Type.UInt:
6474 return new UIntConstant (t, 0, loc);
6475 case BuiltinTypeSpec.Type.Long:
6476 return new LongConstant (t, 0, loc);
6477 case BuiltinTypeSpec.Type.ULong:
6478 return new ULongConstant (t, 0, loc);
6479 case BuiltinTypeSpec.Type.Float:
6480 return new FloatConstant (t, 0, loc);
6481 case BuiltinTypeSpec.Type.Double:
6482 return new DoubleConstant (t, 0, loc);
6483 case BuiltinTypeSpec.Type.Short:
6484 return new ShortConstant (t, 0, loc);
6485 case BuiltinTypeSpec.Type.UShort:
6486 return new UShortConstant (t, 0, loc);
6487 case BuiltinTypeSpec.Type.SByte:
6488 return new SByteConstant (t, 0, loc);
6489 case BuiltinTypeSpec.Type.Byte:
6490 return new ByteConstant (t, 0, loc);
6491 case BuiltinTypeSpec.Type.Char:
6492 return new CharConstant (t, '\0', loc);
6493 case BuiltinTypeSpec.Type.Bool:
6494 return new BoolConstant (t, false, loc);
6495 case BuiltinTypeSpec.Type.Decimal:
6496 return new DecimalConstant (t, 0, loc);
6500 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
6502 if (t.IsNullableType)
6503 return Nullable.LiftedNull.Create (t, loc);
6508 public override bool ContainsEmitWithAwait ()
6510 return arguments != null && arguments.ContainsEmitWithAwait ();
6514 // Checks whether the type is an interface that has the
6515 // [ComImport, CoClass] attributes and must be treated
6518 public Expression CheckComImport (ResolveContext ec)
6520 if (!type.IsInterface)
6524 // Turn the call into:
6525 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
6527 var real_class = type.MemberDefinition.GetAttributeCoClass ();
6528 if (real_class == null)
6531 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
6532 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
6533 return cast.Resolve (ec);
6536 public override Expression CreateExpressionTree (ResolveContext ec)
6539 if (method == null) {
6540 args = new Arguments (1);
6541 args.Add (new Argument (new TypeOf (type, loc)));
6543 args = Arguments.CreateForExpressionTree (ec,
6544 arguments, new TypeOfMethod (method, loc));
6547 return CreateExpressionFactoryCall (ec, "New", args);
6550 protected override Expression DoResolve (ResolveContext ec)
6552 type = RequestedType.ResolveAsType (ec);
6556 eclass = ExprClass.Value;
6558 if (type.IsPointer) {
6559 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
6560 type.GetSignatureForError ());
6564 if (arguments == null) {
6565 Constant c = Constantify (type, RequestedType.Location);
6567 return ReducedExpression.Create (c, this);
6570 if (type.IsDelegate) {
6571 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
6574 var tparam = type as TypeParameterSpec;
6575 if (tparam != null) {
6577 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
6578 // where type parameter constraint is inflated to struct
6580 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
6581 ec.Report.Error (304, loc,
6582 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
6583 type.GetSignatureForError ());
6586 if ((arguments != null) && (arguments.Count != 0)) {
6587 ec.Report.Error (417, loc,
6588 "`{0}': cannot provide arguments when creating an instance of a variable type",
6589 type.GetSignatureForError ());
6595 if (type.IsStatic) {
6596 ec.Report.SymbolRelatedToPreviousError (type);
6597 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
6601 if (type.IsInterface || type.IsAbstract){
6602 if (!TypeManager.IsGenericType (type)) {
6603 RequestedType = CheckComImport (ec);
6604 if (RequestedType != null)
6605 return RequestedType;
6608 ec.Report.SymbolRelatedToPreviousError (type);
6609 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
6614 // Any struct always defines parameterless constructor
6616 if (type.IsStruct && arguments == null)
6620 if (arguments != null) {
6621 arguments.Resolve (ec, out dynamic);
6626 method = ConstructorLookup (ec, type, ref arguments, loc);
6629 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
6630 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
6636 bool DoEmitTypeParameter (EmitContext ec)
6638 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
6642 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
6643 var tparam = (TypeParameterSpec) type;
6645 if (tparam.IsReferenceType) {
6646 ec.Emit (OpCodes.Call, ctor_factory);
6650 // Allow DoEmit() to be called multiple times.
6651 // We need to create a new LocalTemporary each time since
6652 // you can't share LocalBuilders among ILGeneators.
6653 LocalTemporary temp = new LocalTemporary (type);
6655 Label label_activator = ec.DefineLabel ();
6656 Label label_end = ec.DefineLabel ();
6658 temp.AddressOf (ec, AddressOp.Store);
6659 ec.Emit (OpCodes.Initobj, type);
6662 ec.Emit (OpCodes.Box, type);
6663 ec.Emit (OpCodes.Brfalse, label_activator);
6665 temp.AddressOf (ec, AddressOp.Store);
6666 ec.Emit (OpCodes.Initobj, type);
6669 ec.Emit (OpCodes.Br_S, label_end);
6671 ec.MarkLabel (label_activator);
6673 ec.Emit (OpCodes.Call, ctor_factory);
6674 ec.MarkLabel (label_end);
6679 // This Emit can be invoked in two contexts:
6680 // * As a mechanism that will leave a value on the stack (new object)
6681 // * As one that wont (init struct)
6683 // If we are dealing with a ValueType, we have a few
6684 // situations to deal with:
6686 // * The target is a ValueType, and we have been provided
6687 // the instance (this is easy, we are being assigned).
6689 // * The target of New is being passed as an argument,
6690 // to a boxing operation or a function that takes a
6693 // In this case, we need to create a temporary variable
6694 // that is the argument of New.
6696 // Returns whether a value is left on the stack
6698 // *** Implementation note ***
6700 // To benefit from this optimization, each assignable expression
6701 // has to manually cast to New and call this Emit.
6703 // TODO: It's worth to implement it for arrays and fields
6705 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
6707 bool is_value_type = TypeSpec.IsValueType (type);
6708 VariableReference vr = target as VariableReference;
6710 if (target != null && is_value_type && (vr != null || method == null)) {
6711 target.AddressOf (ec, AddressOp.Store);
6712 } else if (vr != null && vr.IsRef) {
6716 if (arguments != null) {
6717 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
6718 arguments = arguments.Emit (ec, false, true);
6720 arguments.Emit (ec);
6723 if (is_value_type) {
6724 if (method == null) {
6725 ec.Emit (OpCodes.Initobj, type);
6730 ec.MarkCallEntry (loc);
6731 ec.Emit (OpCodes.Call, method);
6736 if (type is TypeParameterSpec)
6737 return DoEmitTypeParameter (ec);
6739 ec.MarkCallEntry (loc);
6740 ec.Emit (OpCodes.Newobj, method);
6744 public override void Emit (EmitContext ec)
6746 LocalTemporary v = null;
6747 if (method == null && TypeSpec.IsValueType (type)) {
6748 // TODO: Use temporary variable from pool
6749 v = new LocalTemporary (type);
6756 public override void EmitStatement (EmitContext ec)
6758 LocalTemporary v = null;
6759 if (method == null && TypeSpec.IsValueType (type)) {
6760 // TODO: Use temporary variable from pool
6761 v = new LocalTemporary (type);
6765 ec.Emit (OpCodes.Pop);
6768 public override void FlowAnalysis (FlowAnalysisContext fc)
6770 if (arguments != null)
6771 arguments.FlowAnalysis (fc);
6774 public void AddressOf (EmitContext ec, AddressOp mode)
6776 EmitAddressOf (ec, mode);
6779 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
6781 LocalTemporary value_target = new LocalTemporary (type);
6783 if (type is TypeParameterSpec) {
6784 DoEmitTypeParameter (ec);
6785 value_target.Store (ec);
6786 value_target.AddressOf (ec, mode);
6787 return value_target;
6790 value_target.AddressOf (ec, AddressOp.Store);
6792 if (method == null) {
6793 ec.Emit (OpCodes.Initobj, type);
6795 if (arguments != null)
6796 arguments.Emit (ec);
6798 ec.Emit (OpCodes.Call, method);
6801 value_target.AddressOf (ec, mode);
6802 return value_target;
6805 protected override void CloneTo (CloneContext clonectx, Expression t)
6807 New target = (New) t;
6809 target.RequestedType = RequestedType.Clone (clonectx);
6810 if (arguments != null){
6811 target.arguments = arguments.Clone (clonectx);
6815 public override SLE.Expression MakeExpression (BuilderContext ctx)
6818 return base.MakeExpression (ctx);
6820 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
6824 public override object Accept (StructuralVisitor visitor)
6826 return visitor.Visit (this);
6831 // Array initializer expression, the expression is allowed in
6832 // variable or field initialization only which makes it tricky as
6833 // the type has to be infered based on the context either from field
6834 // type or variable type (think of multiple declarators)
6836 public class ArrayInitializer : Expression
6838 List<Expression> elements;
6839 BlockVariable variable;
6841 public ArrayInitializer (List<Expression> init, Location loc)
6847 public ArrayInitializer (int count, Location loc)
6848 : this (new List<Expression> (count), loc)
6852 public ArrayInitializer (Location loc)
6860 get { return elements.Count; }
6863 public List<Expression> Elements {
6869 public Expression this [int index] {
6871 return elements [index];
6875 public BlockVariable VariableDeclaration {
6886 public void Add (Expression expr)
6888 elements.Add (expr);
6891 public override bool ContainsEmitWithAwait ()
6893 throw new NotSupportedException ();
6896 public override Expression CreateExpressionTree (ResolveContext ec)
6898 throw new NotSupportedException ("ET");
6901 protected override void CloneTo (CloneContext clonectx, Expression t)
6903 var target = (ArrayInitializer) t;
6905 target.elements = new List<Expression> (elements.Count);
6906 foreach (var element in elements)
6907 target.elements.Add (element.Clone (clonectx));
6910 protected override Expression DoResolve (ResolveContext rc)
6912 var current_field = rc.CurrentMemberDefinition as FieldBase;
6913 TypeExpression type;
6914 if (current_field != null && rc.CurrentAnonymousMethod == null) {
6915 type = new TypeExpression (current_field.MemberType, current_field.Location);
6916 } else if (variable != null) {
6917 if (variable.TypeExpression is VarExpr) {
6918 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6919 return EmptyExpression.Null;
6922 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6924 throw new NotImplementedException ("Unexpected array initializer context");
6927 return new ArrayCreation (type, this).Resolve (rc);
6930 public override void Emit (EmitContext ec)
6932 throw new InternalErrorException ("Missing Resolve call");
6935 public override void FlowAnalysis (FlowAnalysisContext fc)
6937 throw new InternalErrorException ("Missing Resolve call");
6940 public override object Accept (StructuralVisitor visitor)
6942 return visitor.Visit (this);
6947 /// 14.5.10.2: Represents an array creation expression.
6951 /// There are two possible scenarios here: one is an array creation
6952 /// expression that specifies the dimensions and optionally the
6953 /// initialization data and the other which does not need dimensions
6954 /// specified but where initialization data is mandatory.
6956 public class ArrayCreation : Expression
6958 FullNamedExpression requested_base_type;
6959 ArrayInitializer initializers;
6962 // The list of Argument types.
6963 // This is used to construct the `newarray' or constructor signature
6965 protected List<Expression> arguments;
6967 protected TypeSpec array_element_type;
6969 protected int dimensions;
6970 protected readonly ComposedTypeSpecifier rank;
6971 Expression first_emit;
6972 LocalTemporary first_emit_temp;
6974 protected List<Expression> array_data;
6976 Dictionary<int, int> bounds;
6979 // The number of constants in array initializers
6980 int const_initializers_count;
6981 bool only_constant_initializers;
6983 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6984 : this (requested_base_type, rank, initializers, l)
6986 arguments = new List<Expression> (exprs);
6987 num_arguments = arguments.Count;
6991 // For expressions like int[] foo = new int[] { 1, 2, 3 };
6993 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6995 this.requested_base_type = requested_base_type;
6997 this.initializers = initializers;
7001 num_arguments = rank.Dimension;
7005 // For compiler generated single dimensional arrays only
7007 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7008 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7013 // For expressions like int[] foo = { 1, 2, 3 };
7015 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7016 : this (requested_base_type, null, initializers, initializers.Location)
7020 public ComposedTypeSpecifier Rank {
7026 public FullNamedExpression TypeExpression {
7028 return this.requested_base_type;
7032 public ArrayInitializer Initializers {
7034 return this.initializers;
7038 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7040 if (initializers != null && bounds == null) {
7042 // We use this to store all the data values in the order in which we
7043 // will need to store them in the byte blob later
7045 array_data = new List<Expression> (probe.Count);
7046 bounds = new Dictionary<int, int> ();
7049 if (specified_dims) {
7050 Expression a = arguments [idx];
7055 a = ConvertExpressionToArrayIndex (ec, a);
7061 if (initializers != null) {
7062 Constant c = a as Constant;
7063 if (c == null && a is ArrayIndexCast)
7064 c = ((ArrayIndexCast) a).Child as Constant;
7067 ec.Report.Error (150, a.Location, "A constant value is expected");
7073 value = System.Convert.ToInt32 (c.GetValue ());
7075 ec.Report.Error (150, a.Location, "A constant value is expected");
7079 // TODO: probe.Count does not fit ulong in
7080 if (value != probe.Count) {
7081 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7085 bounds[idx] = value;
7089 if (initializers == null)
7092 for (int i = 0; i < probe.Count; ++i) {
7094 if (o is ArrayInitializer) {
7095 var sub_probe = o as ArrayInitializer;
7096 if (idx + 1 >= dimensions){
7097 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7101 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7102 if (!bounds.ContainsKey(idx + 1))
7103 bounds[idx + 1] = sub_probe.Count;
7105 if (bounds[idx + 1] != sub_probe.Count) {
7106 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7110 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7113 } else if (child_bounds > 1) {
7114 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7116 Expression element = ResolveArrayElement (ec, o);
7117 if (element == null)
7120 // Initializers with the default values can be ignored
7121 Constant c = element as Constant;
7123 if (!c.IsDefaultInitializer (array_element_type)) {
7124 ++const_initializers_count;
7127 only_constant_initializers = false;
7130 array_data.Add (element);
7137 public override bool ContainsEmitWithAwait ()
7139 foreach (var arg in arguments) {
7140 if (arg.ContainsEmitWithAwait ())
7144 return InitializersContainAwait ();
7147 public override Expression CreateExpressionTree (ResolveContext ec)
7151 if (array_data == null) {
7152 args = new Arguments (arguments.Count + 1);
7153 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7154 foreach (Expression a in arguments)
7155 args.Add (new Argument (a.CreateExpressionTree (ec)));
7157 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7160 if (dimensions > 1) {
7161 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7165 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7166 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7167 if (array_data != null) {
7168 for (int i = 0; i < array_data.Count; ++i) {
7169 Expression e = array_data [i];
7170 args.Add (new Argument (e.CreateExpressionTree (ec)));
7174 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7177 void UpdateIndices (ResolveContext rc)
7180 for (var probe = initializers; probe != null;) {
7181 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7183 bounds[i++] = probe.Count;
7185 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7186 probe = (ArrayInitializer) probe[0];
7187 } else if (dimensions > i) {
7195 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
7197 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
7200 public override void FlowAnalysis (FlowAnalysisContext fc)
7202 foreach (var arg in arguments)
7203 arg.FlowAnalysis (fc);
7205 if (array_data != null) {
7206 foreach (var ad in array_data)
7207 ad.FlowAnalysis (fc);
7211 bool InitializersContainAwait ()
7213 if (array_data == null)
7216 foreach (var expr in array_data) {
7217 if (expr.ContainsEmitWithAwait ())
7224 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
7226 element = element.Resolve (ec);
7227 if (element == null)
7230 if (element is CompoundAssign.TargetExpression) {
7231 if (first_emit != null)
7232 throw new InternalErrorException ("Can only handle one mutator at a time");
7233 first_emit = element;
7234 element = first_emit_temp = new LocalTemporary (element.Type);
7237 return Convert.ImplicitConversionRequired (
7238 ec, element, array_element_type, loc);
7241 protected bool ResolveInitializers (ResolveContext ec)
7244 only_constant_initializers = true;
7247 if (arguments != null) {
7249 for (int i = 0; i < arguments.Count; ++i) {
7250 res &= CheckIndices (ec, initializers, i, true, dimensions);
7251 if (initializers != null)
7258 arguments = new List<Expression> ();
7260 if (!CheckIndices (ec, initializers, 0, false, dimensions))
7269 // Resolved the type of the array
7271 bool ResolveArrayType (ResolveContext ec)
7276 FullNamedExpression array_type_expr;
7277 if (num_arguments > 0) {
7278 array_type_expr = new ComposedCast (requested_base_type, rank);
7280 array_type_expr = requested_base_type;
7283 type = array_type_expr.ResolveAsType (ec);
7284 if (array_type_expr == null)
7287 var ac = type as ArrayContainer;
7289 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
7293 array_element_type = ac.Element;
7294 dimensions = ac.Rank;
7299 protected override Expression DoResolve (ResolveContext ec)
7304 if (!ResolveArrayType (ec))
7308 // validate the initializers and fill in any missing bits
7310 if (!ResolveInitializers (ec))
7313 eclass = ExprClass.Value;
7317 byte [] MakeByteBlob ()
7322 int count = array_data.Count;
7324 TypeSpec element_type = array_element_type;
7325 if (element_type.IsEnum)
7326 element_type = EnumSpec.GetUnderlyingType (element_type);
7328 factor = BuiltinTypeSpec.GetSize (element_type);
7330 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
7332 data = new byte [(count * factor + 3) & ~3];
7335 for (int i = 0; i < count; ++i) {
7336 var c = array_data[i] as Constant;
7342 object v = c.GetValue ();
7344 switch (element_type.BuiltinType) {
7345 case BuiltinTypeSpec.Type.Long:
7346 long lval = (long) v;
7348 for (int j = 0; j < factor; ++j) {
7349 data[idx + j] = (byte) (lval & 0xFF);
7353 case BuiltinTypeSpec.Type.ULong:
7354 ulong ulval = (ulong) v;
7356 for (int j = 0; j < factor; ++j) {
7357 data[idx + j] = (byte) (ulval & 0xFF);
7358 ulval = (ulval >> 8);
7361 case BuiltinTypeSpec.Type.Float:
7362 var fval = SingleConverter.SingleToInt32Bits((float) v);
7364 data[idx] = (byte) (fval & 0xff);
7365 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
7366 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
7367 data[idx + 3] = (byte) (fval >> 24);
7369 case BuiltinTypeSpec.Type.Double:
7370 element = BitConverter.GetBytes ((double) v);
7372 for (int j = 0; j < factor; ++j)
7373 data[idx + j] = element[j];
7375 // FIXME: Handle the ARM float format.
7376 if (!BitConverter.IsLittleEndian)
7377 System.Array.Reverse (data, idx, 8);
7379 case BuiltinTypeSpec.Type.Char:
7380 int chval = (int) ((char) v);
7382 data[idx] = (byte) (chval & 0xff);
7383 data[idx + 1] = (byte) (chval >> 8);
7385 case BuiltinTypeSpec.Type.Short:
7386 int sval = (int) ((short) v);
7388 data[idx] = (byte) (sval & 0xff);
7389 data[idx + 1] = (byte) (sval >> 8);
7391 case BuiltinTypeSpec.Type.UShort:
7392 int usval = (int) ((ushort) v);
7394 data[idx] = (byte) (usval & 0xff);
7395 data[idx + 1] = (byte) (usval >> 8);
7397 case BuiltinTypeSpec.Type.Int:
7400 data[idx] = (byte) (val & 0xff);
7401 data[idx + 1] = (byte) ((val >> 8) & 0xff);
7402 data[idx + 2] = (byte) ((val >> 16) & 0xff);
7403 data[idx + 3] = (byte) (val >> 24);
7405 case BuiltinTypeSpec.Type.UInt:
7406 uint uval = (uint) v;
7408 data[idx] = (byte) (uval & 0xff);
7409 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
7410 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
7411 data[idx + 3] = (byte) (uval >> 24);
7413 case BuiltinTypeSpec.Type.SByte:
7414 data[idx] = (byte) (sbyte) v;
7416 case BuiltinTypeSpec.Type.Byte:
7417 data[idx] = (byte) v;
7419 case BuiltinTypeSpec.Type.Bool:
7420 data[idx] = (byte) ((bool) v ? 1 : 0);
7422 case BuiltinTypeSpec.Type.Decimal:
7423 int[] bits = Decimal.GetBits ((decimal) v);
7426 // FIXME: For some reason, this doesn't work on the MS runtime.
7427 int[] nbits = new int[4];
7433 for (int j = 0; j < 4; j++) {
7434 data[p++] = (byte) (nbits[j] & 0xff);
7435 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
7436 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
7437 data[p++] = (byte) (nbits[j] >> 24);
7441 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
7450 #if NET_4_0 || MOBILE_DYNAMIC
7451 public override SLE.Expression MakeExpression (BuilderContext ctx)
7454 return base.MakeExpression (ctx);
7456 var initializers = new SLE.Expression [array_data.Count];
7457 for (var i = 0; i < initializers.Length; i++) {
7458 if (array_data [i] == null)
7459 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
7461 initializers [i] = array_data [i].MakeExpression (ctx);
7464 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
7470 // Emits the initializers for the array
7472 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
7474 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
7479 // First, the static data
7481 byte [] data = MakeByteBlob ();
7482 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
7484 if (stackArray == null) {
7485 ec.Emit (OpCodes.Dup);
7487 stackArray.Emit (ec);
7490 ec.Emit (OpCodes.Ldtoken, fb);
7491 ec.Emit (OpCodes.Call, m);
7496 // Emits pieces of the array that can not be computed at compile
7497 // time (variables and string locations).
7499 // This always expect the top value on the stack to be the array
7501 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
7503 int dims = bounds.Count;
7504 var current_pos = new int [dims];
7506 for (int i = 0; i < array_data.Count; i++){
7508 Expression e = array_data [i];
7509 var c = e as Constant;
7511 // Constant can be initialized via StaticInitializer
7512 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
7516 if (stackArray != null) {
7517 if (e.ContainsEmitWithAwait ()) {
7518 e = e.EmitToField (ec);
7521 stackArray.EmitLoad (ec);
7523 ec.Emit (OpCodes.Dup);
7526 for (int idx = 0; idx < dims; idx++)
7527 ec.EmitInt (current_pos [idx]);
7530 // If we are dealing with a struct, get the
7531 // address of it, so we can store it.
7533 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
7534 ec.Emit (OpCodes.Ldelema, etype);
7538 ec.EmitArrayStore ((ArrayContainer) type);
7544 for (int j = dims - 1; j >= 0; j--){
7546 if (current_pos [j] < bounds [j])
7548 current_pos [j] = 0;
7552 if (stackArray != null)
7553 stackArray.PrepareCleanup (ec);
7556 public override void Emit (EmitContext ec)
7558 EmitToFieldSource (ec);
7561 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
7563 if (first_emit != null) {
7564 first_emit.Emit (ec);
7565 first_emit_temp.Store (ec);
7568 StackFieldExpr await_stack_field;
7569 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
7570 await_stack_field = ec.GetTemporaryField (type);
7573 await_stack_field = null;
7576 EmitExpressionsList (ec, arguments);
7578 ec.EmitArrayNew ((ArrayContainer) type);
7580 if (initializers == null)
7581 return await_stack_field;
7583 if (await_stack_field != null)
7584 await_stack_field.EmitAssignFromStack (ec);
7588 // Emit static initializer for arrays which contain more than 2 items and
7589 // the static initializer will initialize at least 25% of array values or there
7590 // is more than 10 items to be initialized
7592 // NOTE: const_initializers_count does not contain default constant values.
7594 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
7595 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
7596 EmitStaticInitializers (ec, await_stack_field);
7598 if (!only_constant_initializers)
7599 EmitDynamicInitializers (ec, false, await_stack_field);
7603 EmitDynamicInitializers (ec, true, await_stack_field);
7606 if (first_emit_temp != null)
7607 first_emit_temp.Release (ec);
7609 return await_stack_field;
7612 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7614 // no multi dimensional or jagged arrays
7615 if (arguments.Count != 1 || array_element_type.IsArray) {
7616 base.EncodeAttributeValue (rc, enc, targetType);
7620 // No array covariance, except for array -> object
7621 if (type != targetType) {
7622 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
7623 base.EncodeAttributeValue (rc, enc, targetType);
7627 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
7628 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7633 // Single dimensional array of 0 size
7634 if (array_data == null) {
7635 IntConstant ic = arguments[0] as IntConstant;
7636 if (ic == null || !ic.IsDefaultValue) {
7637 base.EncodeAttributeValue (rc, enc, targetType);
7645 enc.Encode (array_data.Count);
7646 foreach (var element in array_data) {
7647 element.EncodeAttributeValue (rc, enc, array_element_type);
7651 protected override void CloneTo (CloneContext clonectx, Expression t)
7653 ArrayCreation target = (ArrayCreation) t;
7655 if (requested_base_type != null)
7656 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
7658 if (arguments != null){
7659 target.arguments = new List<Expression> (arguments.Count);
7660 foreach (Expression e in arguments)
7661 target.arguments.Add (e.Clone (clonectx));
7664 if (initializers != null)
7665 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
7668 public override object Accept (StructuralVisitor visitor)
7670 return visitor.Visit (this);
7675 // Represents an implicitly typed array epxression
7677 class ImplicitlyTypedArrayCreation : ArrayCreation
7679 TypeInferenceContext best_type_inference;
7681 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7682 : base (null, rank, initializers, loc)
7686 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
7687 : base (null, initializers, loc)
7691 protected override Expression DoResolve (ResolveContext ec)
7696 dimensions = rank.Dimension;
7698 best_type_inference = new TypeInferenceContext ();
7700 if (!ResolveInitializers (ec))
7703 best_type_inference.FixAllTypes (ec);
7704 array_element_type = best_type_inference.InferredTypeArguments[0];
7705 best_type_inference = null;
7707 if (array_element_type == null ||
7708 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
7709 arguments.Count != rank.Dimension) {
7710 ec.Report.Error (826, loc,
7711 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
7716 // At this point we found common base type for all initializer elements
7717 // but we have to be sure that all static initializer elements are of
7720 UnifyInitializerElement (ec);
7722 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
7723 eclass = ExprClass.Value;
7728 // Converts static initializer only
7730 void UnifyInitializerElement (ResolveContext ec)
7732 for (int i = 0; i < array_data.Count; ++i) {
7733 Expression e = array_data[i];
7735 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
7739 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
7741 element = element.Resolve (ec);
7742 if (element != null)
7743 best_type_inference.AddCommonTypeBound (element.Type);
7749 sealed class CompilerGeneratedThis : This
7751 public CompilerGeneratedThis (TypeSpec type, Location loc)
7755 eclass = ExprClass.Variable;
7758 protected override Expression DoResolve (ResolveContext ec)
7763 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7770 /// Represents the `this' construct
7773 public class This : VariableReference
7775 sealed class ThisVariable : ILocalVariable
7777 public static readonly ILocalVariable Instance = new ThisVariable ();
7779 public void Emit (EmitContext ec)
7784 public void EmitAssign (EmitContext ec)
7786 throw new InvalidOperationException ();
7789 public void EmitAddressOf (EmitContext ec)
7795 VariableInfo variable_info;
7797 public This (Location loc)
7804 public override string Name {
7805 get { return "this"; }
7808 public override bool IsLockedByStatement {
7816 public override bool IsRef {
7817 get { return type.IsStruct; }
7820 public override bool IsSideEffectFree {
7826 protected override ILocalVariable Variable {
7827 get { return ThisVariable.Instance; }
7830 public override VariableInfo VariableInfo {
7831 get { return variable_info; }
7834 public override bool IsFixed {
7835 get { return false; }
7840 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
7843 // It's null for all cases when we don't need to check `this'
7844 // definitive assignment
7846 if (variable_info == null)
7849 if (fc.IsDefinitelyAssigned (variable_info))
7852 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
7855 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
7857 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
7858 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7859 } else if (ec.CurrentAnonymousMethod != null) {
7860 ec.Report.Error (1673, loc,
7861 "Anonymous methods inside structs cannot access instance members of `this'. " +
7862 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
7864 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
7868 public override void FlowAnalysis (FlowAnalysisContext fc)
7870 CheckStructThisDefiniteAssignment (fc);
7873 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7878 AnonymousMethodStorey storey = ae.Storey;
7879 return storey != null ? storey.HoistedThis : null;
7882 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
7884 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
7887 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
7890 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
7896 public virtual void ResolveBase (ResolveContext ec)
7898 eclass = ExprClass.Variable;
7899 type = ec.CurrentType;
7901 if (!IsThisAvailable (ec, false)) {
7902 Error_ThisNotAvailable (ec);
7906 var block = ec.CurrentBlock;
7907 if (block != null) {
7908 var top = block.ParametersBlock.TopBlock;
7909 if (top.ThisVariable != null)
7910 variable_info = top.ThisVariable.VariableInfo;
7912 AnonymousExpression am = ec.CurrentAnonymousMethod;
7913 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
7915 // Hoisted this is almost like hoisted variable but not exactly. When
7916 // there is no variable hoisted we can simply emit an instance method
7917 // without lifting this into a storey. Unfotunatelly this complicates
7918 // things in other cases because we don't know where this will be hoisted
7919 // until top-level block is fully resolved
7921 top.AddThisReferenceFromChildrenBlock (block.Explicit);
7922 am.SetHasThisAccess ();
7927 protected override Expression DoResolve (ResolveContext ec)
7933 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7935 if (eclass == ExprClass.Unresolved)
7939 if (right_side == EmptyExpression.UnaryAddress)
7940 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
7941 else if (right_side == EmptyExpression.OutAccess)
7942 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
7944 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
7950 public override int GetHashCode()
7952 throw new NotImplementedException ();
7955 public override bool Equals (object obj)
7957 This t = obj as This;
7964 protected override void CloneTo (CloneContext clonectx, Expression t)
7969 public override void SetHasAddressTaken ()
7974 public override object Accept (StructuralVisitor visitor)
7976 return visitor.Visit (this);
7981 /// Represents the `__arglist' construct
7983 public class ArglistAccess : Expression
7985 public ArglistAccess (Location loc)
7990 protected override void CloneTo (CloneContext clonectx, Expression target)
7995 public override bool ContainsEmitWithAwait ()
8000 public override Expression CreateExpressionTree (ResolveContext ec)
8002 throw new NotSupportedException ("ET");
8005 protected override Expression DoResolve (ResolveContext ec)
8007 eclass = ExprClass.Variable;
8008 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8010 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8011 ec.Report.Error (190, loc,
8012 "The __arglist construct is valid only within a variable argument method");
8018 public override void Emit (EmitContext ec)
8020 ec.Emit (OpCodes.Arglist);
8023 public override object Accept (StructuralVisitor visitor)
8025 return visitor.Visit (this);
8030 /// Represents the `__arglist (....)' construct
8032 public class Arglist : Expression
8034 Arguments arguments;
8036 public Arglist (Location loc)
8041 public Arglist (Arguments args, Location l)
8047 public Arguments Arguments {
8053 public MetaType[] ArgumentTypes {
8055 if (arguments == null)
8056 return MetaType.EmptyTypes;
8058 var retval = new MetaType[arguments.Count];
8059 for (int i = 0; i < retval.Length; i++)
8060 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8066 public override bool ContainsEmitWithAwait ()
8068 throw new NotImplementedException ();
8071 public override Expression CreateExpressionTree (ResolveContext ec)
8073 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8077 protected override Expression DoResolve (ResolveContext ec)
8079 eclass = ExprClass.Variable;
8080 type = InternalType.Arglist;
8081 if (arguments != null) {
8082 bool dynamic; // Can be ignored as there is always only 1 overload
8083 arguments.Resolve (ec, out dynamic);
8089 public override void Emit (EmitContext ec)
8091 if (arguments != null)
8092 arguments.Emit (ec);
8095 protected override void CloneTo (CloneContext clonectx, Expression t)
8097 Arglist target = (Arglist) t;
8099 if (arguments != null)
8100 target.arguments = arguments.Clone (clonectx);
8103 public override object Accept (StructuralVisitor visitor)
8105 return visitor.Visit (this);
8109 public class RefValueExpr : ShimExpression, IAssignMethod
8111 FullNamedExpression texpr;
8113 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8120 public FullNamedExpression TypeExpression {
8126 public override bool ContainsEmitWithAwait ()
8131 protected override Expression DoResolve (ResolveContext rc)
8133 expr = expr.Resolve (rc);
8134 type = texpr.ResolveAsType (rc);
8135 if (expr == null || type == null)
8138 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8139 eclass = ExprClass.Value;
8143 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8145 return DoResolve (rc);
8148 public override void Emit (EmitContext ec)
8151 ec.Emit (OpCodes.Refanyval, type);
8152 ec.EmitLoadFromPtr (type);
8155 public void Emit (EmitContext ec, bool leave_copy)
8157 throw new NotImplementedException ();
8160 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8163 ec.Emit (OpCodes.Refanyval, type);
8166 LocalTemporary temporary = null;
8168 ec.Emit (OpCodes.Dup);
8169 temporary = new LocalTemporary (source.Type);
8170 temporary.Store (ec);
8173 ec.EmitStoreFromPtr (type);
8175 if (temporary != null) {
8176 temporary.Emit (ec);
8177 temporary.Release (ec);
8181 public override object Accept (StructuralVisitor visitor)
8183 return visitor.Visit (this);
8187 public class RefTypeExpr : ShimExpression
8189 public RefTypeExpr (Expression expr, Location loc)
8195 protected override Expression DoResolve (ResolveContext rc)
8197 expr = expr.Resolve (rc);
8201 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8205 type = rc.BuiltinTypes.Type;
8206 eclass = ExprClass.Value;
8210 public override void Emit (EmitContext ec)
8213 ec.Emit (OpCodes.Refanytype);
8214 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8216 ec.Emit (OpCodes.Call, m);
8219 public override object Accept (StructuralVisitor visitor)
8221 return visitor.Visit (this);
8225 public class MakeRefExpr : ShimExpression
8227 public MakeRefExpr (Expression expr, Location loc)
8233 public override bool ContainsEmitWithAwait ()
8235 throw new NotImplementedException ();
8238 protected override Expression DoResolve (ResolveContext rc)
8240 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
8241 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
8242 eclass = ExprClass.Value;
8246 public override void Emit (EmitContext ec)
8248 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
8249 ec.Emit (OpCodes.Mkrefany, expr.Type);
8252 public override object Accept (StructuralVisitor visitor)
8254 return visitor.Visit (this);
8259 /// Implements the typeof operator
8261 public class TypeOf : Expression {
8262 FullNamedExpression QueriedType;
8265 public TypeOf (FullNamedExpression queried_type, Location l)
8267 QueriedType = queried_type;
8272 // Use this constructor for any compiler generated typeof expression
8274 public TypeOf (TypeSpec type, Location loc)
8276 this.typearg = type;
8282 public override bool IsSideEffectFree {
8288 public TypeSpec TypeArgument {
8294 public FullNamedExpression TypeExpression {
8303 protected override void CloneTo (CloneContext clonectx, Expression t)
8305 TypeOf target = (TypeOf) t;
8306 if (QueriedType != null)
8307 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
8310 public override bool ContainsEmitWithAwait ()
8315 public override Expression CreateExpressionTree (ResolveContext ec)
8317 Arguments args = new Arguments (2);
8318 args.Add (new Argument (this));
8319 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8320 return CreateExpressionFactoryCall (ec, "Constant", args);
8323 protected override Expression DoResolve (ResolveContext ec)
8325 if (eclass != ExprClass.Unresolved)
8328 if (typearg == null) {
8330 // Pointer types are allowed without explicit unsafe, they are just tokens
8332 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
8333 typearg = QueriedType.ResolveAsType (ec);
8336 if (typearg == null)
8339 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8340 ec.Report.Error (1962, QueriedType.Location,
8341 "The typeof operator cannot be used on the dynamic type");
8345 type = ec.BuiltinTypes.Type;
8347 // Even though what is returned is a type object, it's treated as a value by the compiler.
8348 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
8349 eclass = ExprClass.Value;
8353 static bool ContainsDynamicType (TypeSpec type)
8355 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
8358 var element_container = type as ElementTypeSpec;
8359 if (element_container != null)
8360 return ContainsDynamicType (element_container.Element);
8362 foreach (var t in type.TypeArguments) {
8363 if (ContainsDynamicType (t)) {
8371 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
8373 // Target type is not System.Type therefore must be object
8374 // and we need to use different encoding sequence
8375 if (targetType != type)
8378 if (typearg is InflatedTypeSpec) {
8381 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
8382 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
8383 typearg.GetSignatureForError ());
8387 gt = gt.DeclaringType;
8388 } while (gt != null);
8391 if (ContainsDynamicType (typearg)) {
8392 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8396 enc.EncodeTypeName (typearg);
8399 public override void Emit (EmitContext ec)
8401 ec.Emit (OpCodes.Ldtoken, typearg);
8402 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
8404 ec.Emit (OpCodes.Call, m);
8407 public override object Accept (StructuralVisitor visitor)
8409 return visitor.Visit (this);
8413 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
8415 public TypeOfMethod (MethodSpec method, Location loc)
8416 : base (method, loc)
8420 protected override Expression DoResolve (ResolveContext ec)
8422 if (member.IsConstructor) {
8423 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
8425 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
8431 return base.DoResolve (ec);
8434 public override void Emit (EmitContext ec)
8436 ec.Emit (OpCodes.Ldtoken, member);
8439 ec.Emit (OpCodes.Castclass, type);
8442 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8444 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
8447 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8449 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
8453 abstract class TypeOfMember<T> : Expression where T : MemberSpec
8455 protected readonly T member;
8457 protected TypeOfMember (T member, Location loc)
8459 this.member = member;
8463 public override bool IsSideEffectFree {
8469 public override bool ContainsEmitWithAwait ()
8474 public override Expression CreateExpressionTree (ResolveContext ec)
8476 Arguments args = new Arguments (2);
8477 args.Add (new Argument (this));
8478 args.Add (new Argument (new TypeOf (type, loc)));
8479 return CreateExpressionFactoryCall (ec, "Constant", args);
8482 protected override Expression DoResolve (ResolveContext ec)
8484 eclass = ExprClass.Value;
8488 public override void Emit (EmitContext ec)
8490 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
8491 PredefinedMember<MethodSpec> p;
8493 p = GetTypeFromHandleGeneric (ec);
8494 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
8496 p = GetTypeFromHandle (ec);
8499 var mi = p.Resolve (loc);
8501 ec.Emit (OpCodes.Call, mi);
8504 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
8505 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
8508 sealed class TypeOfField : TypeOfMember<FieldSpec>
8510 public TypeOfField (FieldSpec field, Location loc)
8515 protected override Expression DoResolve (ResolveContext ec)
8517 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
8521 return base.DoResolve (ec);
8524 public override void Emit (EmitContext ec)
8526 ec.Emit (OpCodes.Ldtoken, member);
8530 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
8532 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
8535 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
8537 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
8542 /// Implements the sizeof expression
8544 public class SizeOf : Expression {
8545 readonly Expression texpr;
8546 TypeSpec type_queried;
8548 public SizeOf (Expression queried_type, Location l)
8550 this.texpr = queried_type;
8554 public override bool IsSideEffectFree {
8560 public Expression TypeExpression {
8566 public override bool ContainsEmitWithAwait ()
8571 public override Expression CreateExpressionTree (ResolveContext ec)
8573 Error_PointerInsideExpressionTree (ec);
8577 protected override Expression DoResolve (ResolveContext ec)
8579 type_queried = texpr.ResolveAsType (ec);
8580 if (type_queried == null)
8583 if (type_queried.IsEnum)
8584 type_queried = EnumSpec.GetUnderlyingType (type_queried);
8586 int size_of = BuiltinTypeSpec.GetSize (type_queried);
8588 return new IntConstant (ec.BuiltinTypes, size_of, loc);
8591 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
8596 ec.Report.Error (233, loc,
8597 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
8598 type_queried.GetSignatureForError ());
8601 type = ec.BuiltinTypes.Int;
8602 eclass = ExprClass.Value;
8606 public override void Emit (EmitContext ec)
8608 ec.Emit (OpCodes.Sizeof, type_queried);
8611 protected override void CloneTo (CloneContext clonectx, Expression t)
8615 public override object Accept (StructuralVisitor visitor)
8617 return visitor.Visit (this);
8622 /// Implements the qualified-alias-member (::) expression.
8624 public class QualifiedAliasMember : MemberAccess
8626 readonly string alias;
8627 public static readonly string GlobalAlias = "global";
8629 public QualifiedAliasMember (string alias, string identifier, Location l)
8630 : base (null, identifier, l)
8635 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
8636 : base (null, identifier, targs, l)
8641 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
8642 : base (null, identifier, arity, l)
8647 public string Alias {
8653 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
8655 if (alias == GlobalAlias) {
8656 expr = new NamespaceExpression (ec.Module.GlobalRootNamespace, loc);
8657 return base.ResolveAsTypeOrNamespace (ec);
8660 int errors = ec.Module.Compiler.Report.Errors;
8661 expr = ec.LookupNamespaceAlias (alias);
8663 if (errors == ec.Module.Compiler.Report.Errors)
8664 ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
8668 return base.ResolveAsTypeOrNamespace (ec);
8671 protected override Expression DoResolve (ResolveContext ec)
8673 return ResolveAsTypeOrNamespace (ec);
8676 public override string GetSignatureForError ()
8679 if (targs != null) {
8680 name = Name + "<" + targs.GetSignatureForError () + ">";
8683 return alias + "::" + name;
8686 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8688 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
8689 rc.Module.Compiler.Report.Error (687, loc,
8690 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
8691 GetSignatureForError ());
8696 return DoResolve (rc);
8699 protected override void CloneTo (CloneContext clonectx, Expression t)
8704 public override object Accept (StructuralVisitor visitor)
8706 return visitor.Visit (this);
8711 /// Implements the member access expression
8713 public class MemberAccess : ATypeNameExpression
8715 protected Expression expr;
8717 public MemberAccess (Expression expr, string id)
8718 : base (id, expr.Location)
8723 public MemberAccess (Expression expr, string identifier, Location loc)
8724 : base (identifier, loc)
8729 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
8730 : base (identifier, args, loc)
8735 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
8736 : base (identifier, arity, loc)
8741 public Expression LeftExpression {
8747 public override Location StartLocation {
8749 return expr == null ? loc : expr.StartLocation;
8753 protected override Expression DoResolve (ResolveContext rc)
8755 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
8757 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
8762 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
8764 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
8766 if (e is TypeExpr) {
8767 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
8772 e = e.ResolveLValue (rc, rhs);
8777 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
8779 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
8780 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
8782 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
8785 public static bool IsValidDotExpression (TypeSpec type)
8787 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
8788 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
8790 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8793 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
8795 var sn = expr as SimpleName;
8796 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
8799 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
8802 // Resolve expression which does have type set as we need expression type
8803 // with disable flow analysis as we don't know whether left side expression
8804 // is used as variable or type
8806 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
8807 expr = expr.Resolve (rc);
8808 } else if (expr is TypeParameterExpr) {
8809 expr.Error_UnexpectedKind (rc, flags, sn.Location);
8813 expr = expr.Resolve (rc, flags);
8819 var ns = expr as NamespaceExpression;
8821 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8823 if (retval == null) {
8824 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8828 if (HasTypeArguments)
8829 return new GenericTypeExpr (retval.Type, targs, loc);
8835 TypeSpec expr_type = expr.Type;
8836 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8837 me = expr as MemberExpr;
8839 me.ResolveInstanceExpression (rc, null);
8841 Arguments args = new Arguments (1);
8842 args.Add (new Argument (expr));
8843 return new DynamicMemberBinder (Name, args, loc);
8846 if (!IsValidDotExpression (expr_type)) {
8847 Error_OperatorCannotBeApplied (rc, expr_type);
8851 var lookup_arity = Arity;
8852 bool errorMode = false;
8853 Expression member_lookup;
8855 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
8856 if (member_lookup == null) {
8858 // Try to look for extension method when member lookup failed
8860 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8861 var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
8862 if (methods != null) {
8863 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
8864 if (HasTypeArguments) {
8865 if (!targs.Resolve (rc))
8868 emg.SetTypeArguments (rc, targs);
8871 // TODO: it should really skip the checks bellow
8872 return emg.Resolve (rc);
8878 if (member_lookup == null) {
8879 var dep = expr_type.GetMissingDependencies ();
8881 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
8882 } else if (expr is TypeExpr) {
8883 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8885 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
8891 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
8892 // Leave it to overload resolution to report correct error
8893 } else if (!(member_lookup is TypeExpr)) {
8894 // TODO: rc.SymbolRelatedToPreviousError
8895 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
8900 if (member_lookup != null)
8904 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
8908 TypeExpr texpr = member_lookup as TypeExpr;
8909 if (texpr != null) {
8910 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
8911 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
8912 Name, texpr.GetSignatureForError ());
8915 if (!texpr.Type.IsAccessible (rc)) {
8916 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
8917 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
8921 if (HasTypeArguments) {
8922 return new GenericTypeExpr (member_lookup.Type, targs, loc);
8925 return member_lookup;
8928 me = member_lookup as MemberExpr;
8930 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
8934 me = me.ResolveMemberAccess (rc, expr, sn);
8937 if (!targs.Resolve (rc))
8940 me.SetTypeArguments (rc, targs);
8946 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
8948 FullNamedExpression fexpr = expr as FullNamedExpression;
8949 if (fexpr == null) {
8950 expr.ResolveAsType (rc);
8954 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
8956 if (expr_resolved == null)
8959 var ns = expr_resolved as NamespaceExpression;
8961 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
8963 if (retval == null) {
8964 ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
8965 } else if (HasTypeArguments) {
8966 retval = new GenericTypeExpr (retval.Type, targs, loc);
8967 if (retval.ResolveAsType (rc) == null)
8974 var tnew_expr = expr_resolved.ResolveAsType (rc);
8975 if (tnew_expr == null)
8978 TypeSpec expr_type = tnew_expr;
8979 if (TypeManager.IsGenericParameter (expr_type)) {
8980 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
8981 tnew_expr.GetSignatureForError ());
8985 var qam = this as QualifiedAliasMember;
8987 rc.Module.Compiler.Report.Error (431, loc,
8988 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
8993 TypeSpec nested = null;
8994 while (expr_type != null) {
8995 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
8996 if (nested == null) {
8997 if (expr_type == tnew_expr) {
8998 Error_IdentifierNotFound (rc, expr_type, Name);
9002 expr_type = tnew_expr;
9003 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9004 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9008 if (nested.IsAccessible (rc))
9012 // Keep looking after inaccessible candidate but only if
9013 // we are not in same context as the definition itself
9015 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9018 expr_type = expr_type.BaseType;
9023 if (HasTypeArguments) {
9024 texpr = new GenericTypeExpr (nested, targs, loc);
9026 texpr = new GenericOpenTypeExpr (nested, loc);
9029 texpr = new TypeExpression (nested, loc);
9032 if (texpr.ResolveAsType (rc) == null)
9038 protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
9040 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9042 if (nested != null) {
9043 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9047 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9048 if (any_other_member != null) {
9049 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9053 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9054 Name, expr_type.GetSignatureForError ());
9057 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9059 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9062 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9064 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9065 ec.Report.SymbolRelatedToPreviousError (type);
9067 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9069 // a using directive or an assembly reference
9071 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9073 missing = "an assembly reference";
9076 ec.Report.Error (1061, loc,
9077 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9078 type.GetSignatureForError (), name, missing);
9082 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9085 public override string GetSignatureForError ()
9087 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9090 protected override void CloneTo (CloneContext clonectx, Expression t)
9092 MemberAccess target = (MemberAccess) t;
9094 target.expr = expr.Clone (clonectx);
9097 public override object Accept (StructuralVisitor visitor)
9099 return visitor.Visit (this);
9104 /// Implements checked expressions
9106 public class CheckedExpr : Expression {
9108 public Expression Expr;
9110 public CheckedExpr (Expression e, Location l)
9116 public override bool ContainsEmitWithAwait ()
9118 return Expr.ContainsEmitWithAwait ();
9121 public override Expression CreateExpressionTree (ResolveContext ec)
9123 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9124 return Expr.CreateExpressionTree (ec);
9127 protected override Expression DoResolve (ResolveContext ec)
9129 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
9130 Expr = Expr.Resolve (ec);
9135 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9138 eclass = Expr.eclass;
9143 public override void Emit (EmitContext ec)
9145 using (ec.With (EmitContext.Options.CheckedScope, true))
9149 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9151 using (ec.With (EmitContext.Options.CheckedScope, true))
9152 Expr.EmitBranchable (ec, target, on_true);
9155 public override void FlowAnalysis (FlowAnalysisContext fc)
9157 Expr.FlowAnalysis (fc);
9160 public override SLE.Expression MakeExpression (BuilderContext ctx)
9162 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9163 return Expr.MakeExpression (ctx);
9167 protected override void CloneTo (CloneContext clonectx, Expression t)
9169 CheckedExpr target = (CheckedExpr) t;
9171 target.Expr = Expr.Clone (clonectx);
9174 public override object Accept (StructuralVisitor visitor)
9176 return visitor.Visit (this);
9181 /// Implements the unchecked expression
9183 public class UnCheckedExpr : Expression {
9185 public Expression Expr;
9187 public UnCheckedExpr (Expression e, Location l)
9193 public override bool ContainsEmitWithAwait ()
9195 return Expr.ContainsEmitWithAwait ();
9198 public override Expression CreateExpressionTree (ResolveContext ec)
9200 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9201 return Expr.CreateExpressionTree (ec);
9204 protected override Expression DoResolve (ResolveContext ec)
9206 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
9207 Expr = Expr.Resolve (ec);
9212 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
9215 eclass = Expr.eclass;
9220 public override void Emit (EmitContext ec)
9222 using (ec.With (EmitContext.Options.CheckedScope, false))
9226 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
9228 using (ec.With (EmitContext.Options.CheckedScope, false))
9229 Expr.EmitBranchable (ec, target, on_true);
9232 public override void FlowAnalysis (FlowAnalysisContext fc)
9234 Expr.FlowAnalysis (fc);
9237 protected override void CloneTo (CloneContext clonectx, Expression t)
9239 UnCheckedExpr target = (UnCheckedExpr) t;
9241 target.Expr = Expr.Clone (clonectx);
9244 public override object Accept (StructuralVisitor visitor)
9246 return visitor.Visit (this);
9251 /// An Element Access expression.
9253 /// During semantic analysis these are transformed into
9254 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
9256 public class ElementAccess : Expression
9258 public Arguments Arguments;
9259 public Expression Expr;
9261 public ElementAccess (Expression e, Arguments args, Location loc)
9265 this.Arguments = args;
9268 public override Location StartLocation {
9270 return Expr.StartLocation;
9274 public override bool ContainsEmitWithAwait ()
9276 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
9280 // We perform some simple tests, and then to "split" the emit and store
9281 // code we create an instance of a different class, and return that.
9283 Expression CreateAccessExpression (ResolveContext ec)
9286 return (new ArrayAccess (this, loc));
9289 return MakePointerAccess (ec, type);
9291 FieldExpr fe = Expr as FieldExpr;
9293 var ff = fe.Spec as FixedFieldSpec;
9295 return MakePointerAccess (ec, ff.ElementType);
9299 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
9300 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9301 return new IndexerExpr (indexers, type, this);
9304 if (type != InternalType.ErrorType) {
9305 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
9306 type.GetSignatureForError ());
9312 public override Expression CreateExpressionTree (ResolveContext ec)
9314 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
9315 Expr.CreateExpressionTree (ec));
9317 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
9320 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
9322 if (Arguments.Count != 1){
9323 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
9327 var arg = Arguments[0];
9328 if (arg is NamedArgument)
9329 Error_NamedArgument ((NamedArgument) arg, rc.Report);
9331 var index = arg.Expr.Resolve (rc);
9335 index = ConvertExpressionToArrayIndex (rc, index, true);
9337 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
9338 return new Indirection (p, loc);
9341 protected override Expression DoResolve (ResolveContext ec)
9343 Expr = Expr.Resolve (ec);
9349 // TODO: Create 1 result for Resolve and ResolveLValue ?
9350 var res = CreateAccessExpression (ec);
9354 return res.Resolve (ec);
9357 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
9359 Expr = Expr.Resolve (ec);
9365 var res = CreateAccessExpression (ec);
9369 return res.ResolveLValue (ec, rhs);
9372 public override void Emit (EmitContext ec)
9374 throw new Exception ("Should never be reached");
9377 public static void Error_NamedArgument (NamedArgument na, Report Report)
9379 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
9382 public override void FlowAnalysis (FlowAnalysisContext fc)
9384 Expr.FlowAnalysis (fc);
9385 Arguments.FlowAnalysis (fc);
9388 public override string GetSignatureForError ()
9390 return Expr.GetSignatureForError ();
9393 protected override void CloneTo (CloneContext clonectx, Expression t)
9395 ElementAccess target = (ElementAccess) t;
9397 target.Expr = Expr.Clone (clonectx);
9398 if (Arguments != null)
9399 target.Arguments = Arguments.Clone (clonectx);
9402 public override object Accept (StructuralVisitor visitor)
9404 return visitor.Visit (this);
9409 /// Implements array access
9411 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
9413 // Points to our "data" repository
9417 LocalTemporary temp;
9419 bool? has_await_args;
9421 public ArrayAccess (ElementAccess ea_data, Location l)
9427 public void AddressOf (EmitContext ec, AddressOp mode)
9429 var ac = (ArrayContainer) ea.Expr.Type;
9431 LoadInstanceAndArguments (ec, false, false);
9433 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
9434 ec.Emit (OpCodes.Readonly);
9436 ec.EmitArrayAddress (ac);
9439 public override Expression CreateExpressionTree (ResolveContext ec)
9441 return ea.CreateExpressionTree (ec);
9444 public override bool ContainsEmitWithAwait ()
9446 return ea.ContainsEmitWithAwait ();
9449 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9451 return DoResolve (ec);
9454 protected override Expression DoResolve (ResolveContext ec)
9456 // dynamic is used per argument in ConvertExpressionToArrayIndex case
9458 ea.Arguments.Resolve (ec, out dynamic);
9460 var ac = ea.Expr.Type as ArrayContainer;
9461 int rank = ea.Arguments.Count;
9462 if (ac.Rank != rank) {
9463 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
9464 rank.ToString (), ac.Rank.ToString ());
9469 if (type.IsPointer && !ec.IsUnsafe) {
9470 UnsafeError (ec, ea.Location);
9473 foreach (Argument a in ea.Arguments) {
9474 if (a is NamedArgument)
9475 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
9477 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
9480 eclass = ExprClass.Variable;
9485 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
9487 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
9490 public override void FlowAnalysis (FlowAnalysisContext fc)
9492 ea.FlowAnalysis (fc);
9496 // Load the array arguments into the stack.
9498 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
9501 ea.Expr = ea.Expr.EmitToField (ec);
9502 } else if (duplicateArguments) {
9504 ec.Emit (OpCodes.Dup);
9506 var copy = new LocalTemporary (ea.Expr.Type);
9513 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
9514 if (dup_args != null)
9515 ea.Arguments = dup_args;
9518 public void Emit (EmitContext ec, bool leave_copy)
9520 var ac = ea.Expr.Type as ArrayContainer;
9523 ec.EmitLoadFromPtr (type);
9525 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
9526 LoadInstanceAndArguments (ec, false, true);
9529 LoadInstanceAndArguments (ec, false, false);
9530 ec.EmitArrayLoad (ac);
9534 ec.Emit (OpCodes.Dup);
9535 temp = new LocalTemporary (this.type);
9540 public override void Emit (EmitContext ec)
9545 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9547 var ac = (ArrayContainer) ea.Expr.Type;
9548 TypeSpec t = source.Type;
9550 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
9553 // When we are dealing with a struct, get the address of it to avoid value copy
9554 // Same cannot be done for reference type because array covariance and the
9555 // check in ldelema requires to specify the type of array element stored at the index
9557 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
9558 LoadInstanceAndArguments (ec, false, has_await_args.Value);
9560 if (has_await_args.Value) {
9561 if (source.ContainsEmitWithAwait ()) {
9562 source = source.EmitToField (ec);
9567 LoadInstanceAndArguments (ec, isCompound, false);
9572 ec.EmitArrayAddress (ac);
9575 ec.Emit (OpCodes.Dup);
9579 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
9581 if (has_await_args.Value) {
9582 if (source.ContainsEmitWithAwait ())
9583 source = source.EmitToField (ec);
9585 LoadInstanceAndArguments (ec, false, false);
9592 var lt = ea.Expr as LocalTemporary;
9598 ec.Emit (OpCodes.Dup);
9599 temp = new LocalTemporary (this.type);
9604 ec.EmitStoreFromPtr (t);
9606 ec.EmitArrayStore (ac);
9615 public override Expression EmitToField (EmitContext ec)
9618 // Have to be specialized for arrays to get access to
9619 // underlying element. Instead of another result copy we
9620 // need direct access to element
9624 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
9626 ea.Expr = ea.Expr.EmitToField (ec);
9630 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9632 #if NET_4_0 || MOBILE_DYNAMIC
9633 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9635 throw new NotImplementedException ();
9639 public override SLE.Expression MakeExpression (BuilderContext ctx)
9641 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
9644 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
9646 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
9647 return Arguments.MakeExpression (ea.Arguments, ctx);
9653 // Indexer access expression
9655 sealed class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
9657 IList<MemberSpec> indexers;
9658 Arguments arguments;
9659 TypeSpec queried_type;
9661 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
9662 : base (ea.Location)
9664 this.indexers = indexers;
9665 this.queried_type = queriedType;
9666 this.InstanceExpression = ea.Expr;
9667 this.arguments = ea.Arguments;
9672 protected override Arguments Arguments {
9681 protected override TypeSpec DeclaringType {
9683 return best_candidate.DeclaringType;
9687 public override bool IsInstance {
9693 public override bool IsStatic {
9699 public override string KindName {
9700 get { return "indexer"; }
9703 public override string Name {
9711 public override bool ContainsEmitWithAwait ()
9713 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
9716 public override Expression CreateExpressionTree (ResolveContext ec)
9718 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
9719 InstanceExpression.CreateExpressionTree (ec),
9720 new TypeOfMethod (Getter, loc));
9722 return CreateExpressionFactoryCall (ec, "Call", args);
9725 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9727 LocalTemporary await_source_arg = null;
9730 emitting_compound_assignment = true;
9731 if (source is DynamicExpressionStatement) {
9736 emitting_compound_assignment = false;
9738 if (has_await_arguments) {
9739 await_source_arg = new LocalTemporary (Type);
9740 await_source_arg.Store (ec);
9742 arguments.Add (new Argument (await_source_arg));
9745 temp = await_source_arg;
9748 has_await_arguments = false;
9753 ec.Emit (OpCodes.Dup);
9754 temp = new LocalTemporary (Type);
9760 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
9761 source = source.EmitToField (ec);
9763 temp = new LocalTemporary (Type);
9770 arguments.Add (new Argument (source));
9773 var call = new CallEmitter ();
9774 call.InstanceExpression = InstanceExpression;
9775 if (arguments == null)
9776 call.InstanceExpressionOnStack = true;
9778 call.Emit (ec, Setter, arguments, loc);
9783 } else if (leave_copy) {
9787 if (await_source_arg != null) {
9788 await_source_arg.Release (ec);
9792 public override void FlowAnalysis (FlowAnalysisContext fc)
9794 // TODO: Check the order
9795 base.FlowAnalysis (fc);
9796 arguments.FlowAnalysis (fc);
9799 public override string GetSignatureForError ()
9801 return best_candidate.GetSignatureForError ();
9804 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
9807 throw new NotSupportedException ();
9809 var value = new[] { source.MakeExpression (ctx) };
9810 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
9811 #if NET_4_0 || MOBILE_DYNAMIC
9812 return SLE.Expression.Block (
9813 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
9816 return args.First ();
9821 public override SLE.Expression MakeExpression (BuilderContext ctx)
9824 return base.MakeExpression (ctx);
9826 var args = Arguments.MakeExpression (arguments, ctx);
9827 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
9831 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
9833 if (best_candidate != null)
9836 eclass = ExprClass.IndexerAccess;
9839 arguments.Resolve (rc, out dynamic);
9841 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9844 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
9845 res.BaseMembersProvider = this;
9846 res.InstanceQualifier = this;
9848 // TODO: Do I need 2 argument sets?
9849 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
9850 if (best_candidate != null)
9851 type = res.BestCandidateReturnType;
9852 else if (!res.BestCandidateIsDynamic)
9857 // It has dynamic arguments
9860 Arguments args = new Arguments (arguments.Count + 1);
9862 rc.Report.Error (1972, loc,
9863 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
9865 args.Add (new Argument (InstanceExpression));
9867 args.AddRange (arguments);
9869 best_candidate = null;
9870 return new DynamicIndexBinder (args, loc);
9874 // Try to avoid resolving left expression again
9876 if (right_side != null)
9877 ResolveInstanceExpression (rc, right_side);
9882 protected override void CloneTo (CloneContext clonectx, Expression t)
9884 IndexerExpr target = (IndexerExpr) t;
9886 if (arguments != null)
9887 target.arguments = arguments.Clone (clonectx);
9890 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
9892 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
9895 #region IBaseMembersProvider Members
9897 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
9899 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
9902 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
9904 if (queried_type == member.DeclaringType)
9907 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
9908 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
9911 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
9920 // A base access expression
9922 public class BaseThis : This
9924 public BaseThis (Location loc)
9929 public BaseThis (TypeSpec type, Location loc)
9933 eclass = ExprClass.Variable;
9938 public override string Name {
9946 public override Expression CreateExpressionTree (ResolveContext ec)
9948 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
9949 return base.CreateExpressionTree (ec);
9952 public override void Emit (EmitContext ec)
9956 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
9957 var context_type = ec.CurrentType;
9958 ec.Emit (OpCodes.Ldobj, context_type);
9959 ec.Emit (OpCodes.Box, context_type);
9963 protected override void Error_ThisNotAvailable (ResolveContext ec)
9966 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
9968 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
9972 public override void ResolveBase (ResolveContext ec)
9974 base.ResolveBase (ec);
9975 type = ec.CurrentType.BaseType;
9978 public override object Accept (StructuralVisitor visitor)
9980 return visitor.Visit (this);
9985 /// This class exists solely to pass the Type around and to be a dummy
9986 /// that can be passed to the conversion functions (this is used by
9987 /// foreach implementation to typecast the object return value from
9988 /// get_Current into the proper type. All code has been generated and
9989 /// we only care about the side effect conversions to be performed
9991 /// This is also now used as a placeholder where a no-action expression
9992 /// is needed (the `New' class).
9994 public class EmptyExpression : Expression
9996 sealed class OutAccessExpression : EmptyExpression
9998 public OutAccessExpression (TypeSpec t)
10003 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10005 rc.Report.Error (206, right_side.Location,
10006 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10012 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10013 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10014 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10015 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10016 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10017 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10018 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10019 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10021 public EmptyExpression (TypeSpec t)
10024 eclass = ExprClass.Value;
10025 loc = Location.Null;
10028 protected override void CloneTo (CloneContext clonectx, Expression target)
10032 public override bool ContainsEmitWithAwait ()
10037 public override Expression CreateExpressionTree (ResolveContext ec)
10039 throw new NotSupportedException ("ET");
10042 protected override Expression DoResolve (ResolveContext ec)
10047 public override void Emit (EmitContext ec)
10049 // nothing, as we only exist to not do anything.
10052 public override void EmitSideEffect (EmitContext ec)
10056 public override object Accept (StructuralVisitor visitor)
10058 return visitor.Visit (this);
10062 sealed class EmptyAwaitExpression : EmptyExpression
10064 public EmptyAwaitExpression (TypeSpec type)
10069 public override bool ContainsEmitWithAwait ()
10076 // Empty statement expression
10078 public sealed class EmptyExpressionStatement : ExpressionStatement
10080 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
10082 private EmptyExpressionStatement ()
10084 loc = Location.Null;
10087 public override bool ContainsEmitWithAwait ()
10092 public override Expression CreateExpressionTree (ResolveContext ec)
10097 public override void EmitStatement (EmitContext ec)
10102 protected override Expression DoResolve (ResolveContext ec)
10104 eclass = ExprClass.Value;
10105 type = ec.BuiltinTypes.Object;
10109 public override void Emit (EmitContext ec)
10114 public override object Accept (StructuralVisitor visitor)
10116 return visitor.Visit (this);
10120 public class ErrorExpression : EmptyExpression
10122 public static readonly ErrorExpression Instance = new ErrorExpression ();
10124 private ErrorExpression ()
10125 : base (InternalType.ErrorType)
10129 public override Expression CreateExpressionTree (ResolveContext ec)
10134 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10139 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
10143 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
10147 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
10151 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
10155 public override object Accept (StructuralVisitor visitor)
10157 return visitor.Visit (this);
10161 public class UserCast : Expression {
10165 public UserCast (MethodSpec method, Expression source, Location l)
10167 if (source == null)
10168 throw new ArgumentNullException ("source");
10170 this.method = method;
10171 this.source = source;
10172 type = method.ReturnType;
10176 public Expression Source {
10182 public override bool ContainsEmitWithAwait ()
10184 return source.ContainsEmitWithAwait ();
10187 public override Expression CreateExpressionTree (ResolveContext ec)
10189 Arguments args = new Arguments (3);
10190 args.Add (new Argument (source.CreateExpressionTree (ec)));
10191 args.Add (new Argument (new TypeOf (type, loc)));
10192 args.Add (new Argument (new TypeOfMethod (method, loc)));
10193 return CreateExpressionFactoryCall (ec, "Convert", args);
10196 protected override Expression DoResolve (ResolveContext ec)
10198 ObsoleteAttribute oa = method.GetAttributeObsolete ();
10200 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
10202 eclass = ExprClass.Value;
10206 public override void Emit (EmitContext ec)
10209 ec.MarkCallEntry (loc);
10210 ec.Emit (OpCodes.Call, method);
10213 public override void FlowAnalysis (FlowAnalysisContext fc)
10215 source.FlowAnalysis (fc);
10218 public override string GetSignatureForError ()
10220 return TypeManager.CSharpSignature (method);
10223 public override SLE.Expression MakeExpression (BuilderContext ctx)
10226 return base.MakeExpression (ctx);
10228 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
10234 // Holds additional type specifiers like ?, *, []
10236 public class ComposedTypeSpecifier
10238 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
10240 public readonly int Dimension;
10241 public readonly Location Location;
10243 public ComposedTypeSpecifier (int specifier, Location loc)
10245 this.Dimension = specifier;
10246 this.Location = loc;
10250 public bool IsNullable {
10252 return Dimension == -1;
10256 public bool IsPointer {
10258 return Dimension == -2;
10262 public ComposedTypeSpecifier Next { get; set; }
10266 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
10268 return new ComposedTypeSpecifier (dimension, loc);
10271 public static ComposedTypeSpecifier CreateNullable (Location loc)
10273 return new ComposedTypeSpecifier (-1, loc);
10276 public static ComposedTypeSpecifier CreatePointer (Location loc)
10278 return new ComposedTypeSpecifier (-2, loc);
10281 public string GetSignatureForError ()
10286 ArrayContainer.GetPostfixSignature (Dimension);
10288 return Next != null ? s + Next.GetSignatureForError () : s;
10293 // This class is used to "construct" the type during a typecast
10294 // operation. Since the Type.GetType class in .NET can parse
10295 // the type specification, we just use this to construct the type
10296 // one bit at a time.
10298 public class ComposedCast : TypeExpr {
10299 FullNamedExpression left;
10300 ComposedTypeSpecifier spec;
10302 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
10305 throw new ArgumentNullException ("spec");
10309 this.loc = left.Location;
10312 public override TypeSpec ResolveAsType (IMemberContext ec)
10314 type = left.ResolveAsType (ec);
10318 eclass = ExprClass.Type;
10320 var single_spec = spec;
10322 if (single_spec.IsNullable) {
10323 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
10327 single_spec = single_spec.Next;
10328 } else if (single_spec.IsPointer) {
10329 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
10332 if (!ec.IsUnsafe) {
10333 UnsafeError (ec.Module.Compiler.Report, loc);
10337 type = PointerContainer.MakeType (ec.Module, type);
10338 single_spec = single_spec.Next;
10339 } while (single_spec != null && single_spec.IsPointer);
10342 if (single_spec != null && single_spec.Dimension > 0) {
10343 if (type.IsSpecialRuntimeType) {
10344 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
10345 } else if (type.IsStatic) {
10346 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
10347 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
10348 type.GetSignatureForError ());
10350 MakeArray (ec.Module, single_spec);
10357 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
10359 if (spec.Next != null)
10360 MakeArray (module, spec.Next);
10362 type = ArrayContainer.MakeType (module, type, spec.Dimension);
10365 public override string GetSignatureForError ()
10367 return left.GetSignatureForError () + spec.GetSignatureForError ();
10370 public override object Accept (StructuralVisitor visitor)
10372 return visitor.Visit (this);
10376 class FixedBufferPtr : Expression
10378 readonly Expression array;
10380 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
10382 this.type = array_type;
10383 this.array = array;
10387 public override bool ContainsEmitWithAwait ()
10389 throw new NotImplementedException ();
10392 public override Expression CreateExpressionTree (ResolveContext ec)
10394 Error_PointerInsideExpressionTree (ec);
10398 public override void Emit(EmitContext ec)
10403 protected override Expression DoResolve (ResolveContext ec)
10405 type = PointerContainer.MakeType (ec.Module, type);
10406 eclass = ExprClass.Value;
10413 // This class is used to represent the address of an array, used
10414 // only by the Fixed statement, this generates "&a [0]" construct
10415 // for fixed (char *pa = a)
10417 class ArrayPtr : FixedBufferPtr
10419 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
10420 base (array, array_type, l)
10424 public override void Emit (EmitContext ec)
10429 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
10434 // Encapsulates a conversion rules required for array indexes
10436 public class ArrayIndexCast : TypeCast
10438 public ArrayIndexCast (Expression expr, TypeSpec returnType)
10439 : base (expr, returnType)
10441 if (expr.Type == returnType) // int -> int
10442 throw new ArgumentException ("unnecessary array index conversion");
10445 public override Expression CreateExpressionTree (ResolveContext ec)
10447 using (ec.Set (ResolveContext.Options.CheckedScope)) {
10448 return base.CreateExpressionTree (ec);
10452 public override void Emit (EmitContext ec)
10456 switch (child.Type.BuiltinType) {
10457 case BuiltinTypeSpec.Type.UInt:
10458 ec.Emit (OpCodes.Conv_U);
10460 case BuiltinTypeSpec.Type.Long:
10461 ec.Emit (OpCodes.Conv_Ovf_I);
10463 case BuiltinTypeSpec.Type.ULong:
10464 ec.Emit (OpCodes.Conv_Ovf_I_Un);
10467 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
10473 // Implements the `stackalloc' keyword
10475 public class StackAlloc : Expression {
10480 public StackAlloc (Expression type, Expression count, Location l)
10483 this.count = count;
10487 public Expression TypeExpression {
10493 public Expression CountExpression {
10499 public override bool ContainsEmitWithAwait ()
10504 public override Expression CreateExpressionTree (ResolveContext ec)
10506 throw new NotSupportedException ("ET");
10509 protected override Expression DoResolve (ResolveContext ec)
10511 count = count.Resolve (ec);
10515 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
10516 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
10521 Constant c = count as Constant;
10522 if (c != null && c.IsNegative) {
10523 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
10526 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
10527 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
10530 otype = t.ResolveAsType (ec);
10534 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
10537 type = PointerContainer.MakeType (ec.Module, otype);
10538 eclass = ExprClass.Value;
10543 public override void Emit (EmitContext ec)
10545 int size = BuiltinTypeSpec.GetSize (otype);
10550 ec.Emit (OpCodes.Sizeof, otype);
10554 ec.Emit (OpCodes.Mul_Ovf_Un);
10555 ec.Emit (OpCodes.Localloc);
10558 protected override void CloneTo (CloneContext clonectx, Expression t)
10560 StackAlloc target = (StackAlloc) t;
10561 target.count = count.Clone (clonectx);
10562 target.t = t.Clone (clonectx);
10565 public override object Accept (StructuralVisitor visitor)
10567 return visitor.Visit (this);
10572 // An object initializer expression
10574 public class ElementInitializer : Assign
10576 public readonly string Name;
10578 public ElementInitializer (string name, Expression initializer, Location loc)
10579 : base (null, initializer, loc)
10584 protected override void CloneTo (CloneContext clonectx, Expression t)
10586 ElementInitializer target = (ElementInitializer) t;
10587 target.source = source.Clone (clonectx);
10590 public override Expression CreateExpressionTree (ResolveContext ec)
10592 Arguments args = new Arguments (2);
10593 FieldExpr fe = target as FieldExpr;
10595 args.Add (new Argument (fe.CreateTypeOfExpression ()));
10597 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
10600 Expression arg_expr;
10601 var cinit = source as CollectionOrObjectInitializers;
10602 if (cinit == null) {
10604 arg_expr = source.CreateExpressionTree (ec);
10606 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
10607 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
10610 args.Add (new Argument (arg_expr));
10611 return CreateExpressionFactoryCall (ec, mname, args);
10614 protected override Expression DoResolve (ResolveContext ec)
10616 if (source == null)
10617 return EmptyExpressionStatement.Instance;
10619 var t = ec.CurrentInitializerVariable.Type;
10620 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10621 Arguments args = new Arguments (1);
10622 args.Add (new Argument (ec.CurrentInitializerVariable));
10623 target = new DynamicMemberBinder (Name, args, loc);
10626 var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10627 if (member == null) {
10628 member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
10630 if (member != null) {
10631 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
10632 ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
10637 if (member == null) {
10638 Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
10642 if (!(member is PropertyExpr || member is FieldExpr)) {
10643 ec.Report.Error (1913, loc,
10644 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
10645 member.GetSignatureForError ());
10650 var me = member as MemberExpr;
10652 ec.Report.Error (1914, loc,
10653 "Static field or property `{0}' cannot be assigned in an object initializer",
10654 me.GetSignatureForError ());
10658 me.InstanceExpression = ec.CurrentInitializerVariable;
10661 if (source is CollectionOrObjectInitializers) {
10662 Expression previous = ec.CurrentInitializerVariable;
10663 ec.CurrentInitializerVariable = target;
10664 source = source.Resolve (ec);
10665 ec.CurrentInitializerVariable = previous;
10666 if (source == null)
10669 eclass = source.eclass;
10670 type = source.Type;
10674 return base.DoResolve (ec);
10677 public override void EmitStatement (EmitContext ec)
10679 if (source is CollectionOrObjectInitializers)
10682 base.EmitStatement (ec);
10687 // A collection initializer expression
10689 class CollectionElementInitializer : Invocation
10691 public class ElementInitializerArgument : Argument
10693 public ElementInitializerArgument (Expression e)
10699 sealed class AddMemberAccess : MemberAccess
10701 public AddMemberAccess (Expression expr, Location loc)
10702 : base (expr, "Add", loc)
10706 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10708 if (TypeManager.HasElementType (type))
10711 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10715 public CollectionElementInitializer (Expression argument)
10716 : base (null, new Arguments (1))
10718 base.arguments.Add (new ElementInitializerArgument (argument));
10719 this.loc = argument.Location;
10722 public CollectionElementInitializer (List<Expression> arguments, Location loc)
10723 : base (null, new Arguments (arguments.Count))
10725 foreach (Expression e in arguments)
10726 base.arguments.Add (new ElementInitializerArgument (e));
10731 public CollectionElementInitializer (Location loc)
10732 : base (null, null)
10737 public override Expression CreateExpressionTree (ResolveContext ec)
10739 Arguments args = new Arguments (2);
10740 args.Add (new Argument (mg.CreateExpressionTree (ec)));
10742 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
10743 foreach (Argument a in arguments)
10744 expr_initializers.Add (a.CreateExpressionTree (ec));
10746 args.Add (new Argument (new ArrayCreation (
10747 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
10748 return CreateExpressionFactoryCall (ec, "ElementInit", args);
10751 protected override void CloneTo (CloneContext clonectx, Expression t)
10753 CollectionElementInitializer target = (CollectionElementInitializer) t;
10754 if (arguments != null)
10755 target.arguments = arguments.Clone (clonectx);
10758 protected override Expression DoResolve (ResolveContext ec)
10760 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
10762 return base.DoResolve (ec);
10767 // A block of object or collection initializers
10769 public class CollectionOrObjectInitializers : ExpressionStatement
10771 IList<Expression> initializers;
10772 bool is_collection_initialization;
10774 public CollectionOrObjectInitializers (Location loc)
10775 : this (new Expression[0], loc)
10779 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
10781 this.initializers = initializers;
10785 public IList<Expression> Initializers {
10787 return initializers;
10791 public bool IsEmpty {
10793 return initializers.Count == 0;
10797 public bool IsCollectionInitializer {
10799 return is_collection_initialization;
10803 protected override void CloneTo (CloneContext clonectx, Expression target)
10805 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
10807 t.initializers = new List<Expression> (initializers.Count);
10808 foreach (var e in initializers)
10809 t.initializers.Add (e.Clone (clonectx));
10812 public override bool ContainsEmitWithAwait ()
10814 foreach (var e in initializers) {
10815 if (e.ContainsEmitWithAwait ())
10822 public override Expression CreateExpressionTree (ResolveContext ec)
10824 return CreateExpressionTree (ec, false);
10827 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
10829 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
10830 foreach (Expression e in initializers) {
10831 Expression expr = e.CreateExpressionTree (ec);
10833 expr_initializers.Add (expr);
10837 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
10839 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
10842 protected override Expression DoResolve (ResolveContext ec)
10844 List<string> element_names = null;
10845 for (int i = 0; i < initializers.Count; ++i) {
10846 Expression initializer = initializers [i];
10847 ElementInitializer element_initializer = initializer as ElementInitializer;
10850 if (element_initializer != null) {
10851 element_names = new List<string> (initializers.Count);
10852 element_names.Add (element_initializer.Name);
10853 } else if (initializer is CompletingExpression){
10854 initializer.Resolve (ec);
10855 throw new InternalErrorException ("This line should never be reached");
10857 var t = ec.CurrentInitializerVariable.Type;
10858 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
10859 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
10860 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
10861 "object initializer because type `{1}' does not implement `{2}' interface",
10862 ec.CurrentInitializerVariable.GetSignatureForError (),
10863 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
10864 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
10867 is_collection_initialization = true;
10870 if (is_collection_initialization != (element_initializer == null)) {
10871 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
10872 is_collection_initialization ? "collection initializer" : "object initializer");
10876 if (!is_collection_initialization) {
10877 if (element_names.Contains (element_initializer.Name)) {
10878 ec.Report.Error (1912, element_initializer.Location,
10879 "An object initializer includes more than one member `{0}' initialization",
10880 element_initializer.Name);
10882 element_names.Add (element_initializer.Name);
10887 Expression e = initializer.Resolve (ec);
10888 if (e == EmptyExpressionStatement.Instance)
10889 initializers.RemoveAt (i--);
10891 initializers [i] = e;
10894 type = ec.CurrentInitializerVariable.Type;
10895 if (is_collection_initialization) {
10896 if (TypeManager.HasElementType (type)) {
10897 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
10898 type.GetSignatureForError ());
10902 eclass = ExprClass.Variable;
10906 public override void Emit (EmitContext ec)
10908 EmitStatement (ec);
10911 public override void EmitStatement (EmitContext ec)
10913 foreach (ExpressionStatement e in initializers) {
10914 // TODO: need location region
10915 ec.Mark (e.Location);
10916 e.EmitStatement (ec);
10920 public override void FlowAnalysis (FlowAnalysisContext fc)
10922 foreach (var initializer in initializers)
10923 initializer.FlowAnalysis (fc);
10928 // New expression with element/object initializers
10930 public class NewInitialize : New
10933 // This class serves as a proxy for variable initializer target instances.
10934 // A real variable is assigned later when we resolve left side of an
10937 sealed class InitializerTargetExpression : Expression, IMemoryLocation
10939 NewInitialize new_instance;
10941 public InitializerTargetExpression (NewInitialize newInstance)
10943 this.type = newInstance.type;
10944 this.loc = newInstance.loc;
10945 this.eclass = newInstance.eclass;
10946 this.new_instance = newInstance;
10949 public override bool ContainsEmitWithAwait ()
10954 public override Expression CreateExpressionTree (ResolveContext ec)
10956 // Should not be reached
10957 throw new NotSupportedException ("ET");
10960 protected override Expression DoResolve (ResolveContext ec)
10965 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10970 public override void Emit (EmitContext ec)
10972 Expression e = (Expression) new_instance.instance;
10976 public override Expression EmitToField (EmitContext ec)
10978 return (Expression) new_instance.instance;
10981 #region IMemoryLocation Members
10983 public void AddressOf (EmitContext ec, AddressOp mode)
10985 new_instance.instance.AddressOf (ec, mode);
10991 CollectionOrObjectInitializers initializers;
10992 IMemoryLocation instance;
10993 DynamicExpressionStatement dynamic;
10995 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
10996 : base (requested_type, arguments, l)
10998 this.initializers = initializers;
11001 public CollectionOrObjectInitializers Initializers {
11003 return initializers;
11007 protected override void CloneTo (CloneContext clonectx, Expression t)
11009 base.CloneTo (clonectx, t);
11011 NewInitialize target = (NewInitialize) t;
11012 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
11015 public override bool ContainsEmitWithAwait ()
11017 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
11020 public override Expression CreateExpressionTree (ResolveContext ec)
11022 Arguments args = new Arguments (2);
11023 args.Add (new Argument (base.CreateExpressionTree (ec)));
11024 if (!initializers.IsEmpty)
11025 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
11027 return CreateExpressionFactoryCall (ec,
11028 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
11032 protected override Expression DoResolve (ResolveContext ec)
11034 Expression e = base.DoResolve (ec);
11038 if (type.IsDelegate) {
11039 ec.Report.Error (1958, Initializers.Location,
11040 "Object and collection initializers cannot be used to instantiate a delegate");
11043 Expression previous = ec.CurrentInitializerVariable;
11044 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
11045 initializers.Resolve (ec);
11046 ec.CurrentInitializerVariable = previous;
11048 dynamic = e as DynamicExpressionStatement;
11049 if (dynamic != null)
11055 public override bool Emit (EmitContext ec, IMemoryLocation target)
11057 bool left_on_stack;
11058 if (dynamic != null) {
11060 left_on_stack = true;
11062 left_on_stack = base.Emit (ec, target);
11065 if (initializers.IsEmpty)
11066 return left_on_stack;
11068 LocalTemporary temp = null;
11070 instance = target as LocalTemporary;
11072 if (instance == null) {
11073 if (!left_on_stack) {
11074 VariableReference vr = target as VariableReference;
11076 // FIXME: This still does not work correctly for pre-set variables
11077 if (vr != null && vr.IsRef)
11078 target.AddressOf (ec, AddressOp.Load);
11080 ((Expression) target).Emit (ec);
11081 left_on_stack = true;
11084 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
11085 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
11087 temp = new LocalTemporary (type);
11092 if (left_on_stack && temp != null)
11095 initializers.Emit (ec);
11097 if (left_on_stack) {
11098 if (temp != null) {
11102 ((Expression) instance).Emit (ec);
11106 return left_on_stack;
11109 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
11111 instance = base.EmitAddressOf (ec, Mode);
11113 if (!initializers.IsEmpty)
11114 initializers.Emit (ec);
11119 public override void FlowAnalysis (FlowAnalysisContext fc)
11121 base.FlowAnalysis (fc);
11122 initializers.FlowAnalysis (fc);
11125 public override object Accept (StructuralVisitor visitor)
11127 return visitor.Visit (this);
11131 public class NewAnonymousType : New
11133 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
11135 List<AnonymousTypeParameter> parameters;
11136 readonly TypeContainer parent;
11137 AnonymousTypeClass anonymous_type;
11139 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
11140 : base (null, null, loc)
11142 this.parameters = parameters;
11143 this.parent = parent;
11146 public List<AnonymousTypeParameter> Parameters {
11148 return this.parameters;
11152 protected override void CloneTo (CloneContext clonectx, Expression target)
11154 if (parameters == null)
11157 NewAnonymousType t = (NewAnonymousType) target;
11158 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
11159 foreach (AnonymousTypeParameter atp in parameters)
11160 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
11163 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
11165 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
11169 type = AnonymousTypeClass.Create (parent, parameters, loc);
11173 int errors = ec.Report.Errors;
11174 type.CreateContainer ();
11175 type.DefineContainer ();
11177 if ((ec.Report.Errors - errors) == 0) {
11178 parent.Module.AddAnonymousType (type);
11179 type.PrepareEmit ();
11185 public override Expression CreateExpressionTree (ResolveContext ec)
11187 if (parameters == null)
11188 return base.CreateExpressionTree (ec);
11190 var init = new ArrayInitializer (parameters.Count, loc);
11191 foreach (var m in anonymous_type.Members) {
11192 var p = m as Property;
11194 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
11197 var ctor_args = new ArrayInitializer (arguments.Count, loc);
11198 foreach (Argument a in arguments)
11199 ctor_args.Add (a.CreateExpressionTree (ec));
11201 Arguments args = new Arguments (3);
11202 args.Add (new Argument (new TypeOfMethod (method, loc)));
11203 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
11204 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
11206 return CreateExpressionFactoryCall (ec, "New", args);
11209 protected override Expression DoResolve (ResolveContext ec)
11211 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
11212 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
11216 if (parameters == null) {
11217 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
11218 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
11219 return base.DoResolve (ec);
11222 bool error = false;
11223 arguments = new Arguments (parameters.Count);
11224 var t_args = new TypeSpec [parameters.Count];
11225 for (int i = 0; i < parameters.Count; ++i) {
11226 Expression e = parameters [i].Resolve (ec);
11232 arguments.Add (new Argument (e));
11233 t_args [i] = e.Type;
11239 anonymous_type = CreateAnonymousType (ec, parameters);
11240 if (anonymous_type == null)
11243 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
11244 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
11245 eclass = ExprClass.Value;
11249 public override object Accept (StructuralVisitor visitor)
11251 return visitor.Visit (this);
11255 public class AnonymousTypeParameter : ShimExpression
11257 public readonly string Name;
11259 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
11260 : base (initializer)
11266 public AnonymousTypeParameter (Parameter parameter)
11267 : base (new SimpleName (parameter.Name, parameter.Location))
11269 this.Name = parameter.Name;
11270 this.loc = parameter.Location;
11273 public override bool Equals (object o)
11275 AnonymousTypeParameter other = o as AnonymousTypeParameter;
11276 return other != null && Name == other.Name;
11279 public override int GetHashCode ()
11281 return Name.GetHashCode ();
11284 protected override Expression DoResolve (ResolveContext ec)
11286 Expression e = expr.Resolve (ec);
11290 if (e.eclass == ExprClass.MethodGroup) {
11291 Error_InvalidInitializer (ec, e.ExprClassName);
11296 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
11297 Error_InvalidInitializer (ec, type.GetSignatureForError ());
11304 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
11306 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
11307 Name, initializer);
11311 public class CatchFilterExpression : BooleanExpression
11313 public CatchFilterExpression (Expression expr, Location loc)